Commit 5f3cba022a184dcd2df3df174e49c6ba1566ad2c
0 parents
initial public commit
Showing
34 changed files
with
7222 additions
and
0 deletions
Show diff stats
1 | +++ a/CMakeLists.txt | |
1 | +#Specify the version being used aswell as the language | |
2 | +cmake_minimum_required(VERSION 3.12) | |
3 | + | |
4 | +#Name your project here | |
5 | +project(siproc) | |
6 | + | |
7 | +#set the module directory | |
8 | +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}") | |
9 | + | |
10 | +#default to release mode | |
11 | +if(NOT CMAKE_BUILD_TYPE) | |
12 | + set(CMAKE_BUILD_TYPE Release) | |
13 | +endif(NOT CMAKE_BUILD_TYPE) | |
14 | + | |
15 | +#build the executable in the binary directory on MS Visual Studio | |
16 | +if ( MSVC ) | |
17 | + SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${OUTPUT_DIRECTORY}") | |
18 | + SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${OUTPUT_DIRECTORY}") | |
19 | + SET( LIBRARY_OUTPUT_DIRECTORY_DEBUG "${OUTPUT_DIRECTORY}") | |
20 | + SET( LIBRARY_OUTPUT_DIRECTORY_RELEASE "${OUTPUT_DIRECTORY}") | |
21 | + add_definitions(-D_CRT_SECURE_NO_WARNINGS) | |
22 | + add_definitions(-D_SCL_SECURE_NO_WARNINGS) | |
23 | +endif ( MSVC ) | |
24 | +#MAYBE REMOVE----------------- | |
25 | +#set C++11 flags if using GCC | |
26 | +if( CMAKE_COMPILER_IS_GNUCC ) | |
27 | + SET( CMAKE_CXX_FLAGS "-std=c++11") | |
28 | + SET( CUDA_NVCC_FLAGS "-std=c++11") | |
29 | +endif( CMAKE_COMPILER_IS_GNUCC ) | |
30 | +#----------------------------- | |
31 | + | |
32 | +#find packages----------------------------------- | |
33 | +#find the pthreads package | |
34 | +find_package(Threads) | |
35 | + | |
36 | +#find the X11 package | |
37 | +find_package(X11) | |
38 | + | |
39 | +#find the STIM library | |
40 | +find_package(STIM REQUIRED) | |
41 | + | |
42 | +#find CUDA, mostly for LA stuff using cuBLAS | |
43 | +find_package(CUDA REQUIRED) | |
44 | + | |
45 | +#find Boost for Unix-based file lists | |
46 | +if( CMAKE_COMPILER_IS_GNUCC ) | |
47 | + find_package(Boost COMPONENTS filesystem system) | |
48 | + if(Boost_FOUND) | |
49 | + include_directories(${Boost_INCLUDE_DIR}) | |
50 | + add_definitions(-DBOOST_PRECOMPILED) | |
51 | + else() | |
52 | + message(FATAL_ERROR "HSIproc requires Boost::filesystem and Boost::system when using GCC") | |
53 | + endif() | |
54 | +else() | |
55 | + find_package(Boost) | |
56 | +endif() | |
57 | + | |
58 | +#find the GLUT library for visualization | |
59 | +find_package(OpenGL REQUIRED) | |
60 | +find_package(GLUT REQUIRED) | |
61 | +if(WIN32) | |
62 | + find_package(GLEW REQUIRED) | |
63 | + include_directories(${GLEW_INCLUDE_DIR}) | |
64 | +endif(WIN32) | |
65 | + | |
66 | +#find LAPACK and supporting link_libraries | |
67 | +find_package(LAPACKE REQUIRED) | |
68 | +#if(MSVC) | |
69 | +# message("Warning: VS2015 made a change to printf and scanf functions that requires linking to legacy_stdio_definitions.lib") | |
70 | +#endif() | |
71 | + | |
72 | +#include include directories | |
73 | +include_directories(${CUDA_INCLUDE_DIRS} | |
74 | + ${LAPACKE_INCLUDE_DIR} | |
75 | + ${STIM_INCLUDE_DIRS} | |
76 | + ${OpenGL_INCLUDE_DIRS} | |
77 | + ${GLUT_INCLUDE_DIR} | |
78 | + "${CMAKE_SOURCE_DIR}/src" | |
79 | +) | |
80 | + | |
81 | +#Assign source files to the appropriate variables to easily associate them with executables | |
82 | +file(GLOB HSIGLOBAL_SRC "${CMAKE_SOURCE_DIR}/src/*.cpp") | |
83 | +file(GLOB HSIPROC_SRC "${CMAKE_SOURCE_DIR}/src/proc/*.cpp") | |
84 | +file(GLOB STIM_CU "${STIM_INCLUDE_DIRS}/stim/envi/*.cu") | |
85 | +file(GLOB HSIVIEW_SRC "${CMAKE_SOURCE_DIR}/src/view/*.cpp") | |
86 | +file(GLOB CARY_FTIR_SRC "${CMAKE_SOURCE_DIR}/src/cary-ftir/*.cpp") | |
87 | +file(GLOB SPERO_SRC "${CMAKE_SOURCE_DIR}/src/spero/*.cpp") | |
88 | +file(GLOB PROGRESS_SRC "${CMAKE_SOURCE_DIR}/src/progress_t.cpp") | |
89 | + | |
90 | +#create the PROC executable---------------------------------------------- | |
91 | +add_executable(siproc | |
92 | + ${HSIPROC_SRC} | |
93 | + ${HSIGLOBAL_SRC} | |
94 | +) | |
95 | + | |
96 | +target_link_libraries(siproc ${CUDA_LIBRARIES} | |
97 | + ${CUDA_CUBLAS_LIBRARIES} | |
98 | + ${CUDA_CUFFT_LIBRARIES} | |
99 | + ${LAPACKE_LIBRARIES} | |
100 | + ${CMAKE_THREAD_LIBS_INIT} | |
101 | + ${X11_LIBRARIES} | |
102 | +) | |
103 | + | |
104 | +#create the VIEW executable---------------------------------------------- | |
105 | +add_executable(siview | |
106 | + ${HSIVIEW_SRC} | |
107 | +) | |
108 | +target_link_libraries(siview | |
109 | + ${CMAKE_THREAD_LIBS_INIT} | |
110 | + ${X11_LIBRARIES} | |
111 | + ${OPENGL_gl_LIBRARY} | |
112 | + ${OPENGL_glu_LIBRARY} | |
113 | + ${GLUT_LIBRARIES} | |
114 | +) | |
115 | +if(WIN32) | |
116 | + target_link_libraries(siview ${GLEW_GLEW_LIBRARY}) | |
117 | +endif(WIN32) | |
118 | + | |
119 | +#create instrument-specific subroutine executables | |
120 | +add_executable(cary-ftir | |
121 | + ${CARY_FTIR_SRC} | |
122 | + ${PROGRESS_SRC} | |
123 | +) | |
124 | +target_link_libraries(cary-ftir | |
125 | + ${CUDA_LIBRARIES} | |
126 | + ${CUDA_CUBLAS_LIBRARIES} | |
127 | + ${CUDA_CUFFT_LIBRARIES} | |
128 | +) | |
129 | + | |
130 | +#create the Agilent system-specific subroutine executable | |
131 | +add_executable(spero | |
132 | + ${SPERO_SRC} | |
133 | + ${PROGRESS_SRC} | |
134 | +) | |
135 | +target_link_libraries(spero | |
136 | + ${CUDA_LIBRARIES} | |
137 | + ${CUDA_CUBLAS_LIBRARIES} | |
138 | + ${CUDA_CUFFT_LIBRARIES} | |
139 | +) | |
140 | + | |
141 | +#if Boost is found, set an environment variable to use with preprocessor directives | |
142 | +if(Boost_FILESYSTEM_FOUND) | |
143 | + target_link_libraries(siproc ${Boost_FILESYSTEM_LIBRARIES} | |
144 | + ${Boost_SYSTEM_LIBRARY} | |
145 | + ) | |
146 | + target_link_libraries(siview | |
147 | + ${Boost_FILESYSTEM_LIBRARIES} | |
148 | + ${Boost_SYSTEM_LIBRARY} | |
149 | + ) | |
150 | + target_link_libraries(spero | |
151 | + ${Boost_FILESYSTEM_LIBRARIES} | |
152 | + ${Boost_SYSTEM_LIBRARY} | |
153 | + ) | |
154 | + | |
155 | + target_link_libraries(cary-ftir | |
156 | + ${Boost_FILESYSTEM_LIBRARIES} | |
157 | + ${Boost_SYSTEM_LIBRARY} | |
158 | + ) | |
159 | +endif(Boost_FILESYSTEM_FOUND) | |
160 | + | |
161 | + | ... | ... |
1 | +++ a/Doxyfile | |
1 | +# Doxyfile 1.8.9.1 | |
2 | + | |
3 | +# This file describes the settings to be used by the documentation system | |
4 | +# doxygen (www.doxygen.org) for a project. | |
5 | +# | |
6 | +# All text after a double hash (##) is considered a comment and is placed in | |
7 | +# front of the TAG it is preceding. | |
8 | +# | |
9 | +# All text after a single hash (#) is considered a comment and will be ignored. | |
10 | +# The format is: | |
11 | +# TAG = value [value, ...] | |
12 | +# For lists, items can also be appended using: | |
13 | +# TAG += value [value, ...] | |
14 | +# Values that contain spaces should be placed between quotes (\" \"). | |
15 | + | |
16 | +#--------------------------------------------------------------------------- | |
17 | +# Project related configuration options | |
18 | +#--------------------------------------------------------------------------- | |
19 | + | |
20 | +# This tag specifies the encoding used for all characters in the config file | |
21 | +# that follow. The default is UTF-8 which is also the encoding used for all text | |
22 | +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv | |
23 | +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv | |
24 | +# for the list of possible encodings. | |
25 | +# The default value is: UTF-8. | |
26 | + | |
27 | +DOXYFILE_ENCODING = UTF-8 | |
28 | + | |
29 | +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by | |
30 | +# double-quotes, unless you are using Doxywizard) that should identify the | |
31 | +# project for which the documentation is generated. This name is used in the | |
32 | +# title of most generated pages and in a few other places. | |
33 | +# The default value is: My Project. | |
34 | + | |
35 | +PROJECT_NAME = "stimlab" | |
36 | + | |
37 | +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This | |
38 | +# could be handy for archiving the generated documentation or if some version | |
39 | +# control system is used. | |
40 | + | |
41 | +PROJECT_NUMBER = | |
42 | + | |
43 | +# Using the PROJECT_BRIEF tag one can provide an optional one line description | |
44 | +# for a project that appears at the top of each page and should give viewer a | |
45 | +# quick idea about the purpose of the project. Keep the description short. | |
46 | + | |
47 | +PROJECT_BRIEF = | |
48 | + | |
49 | +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included | |
50 | +# in the documentation. The maximum height of the logo should not exceed 55 | |
51 | +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy | |
52 | +# the logo to the output directory. | |
53 | + | |
54 | +PROJECT_LOGO = | |
55 | + | |
56 | +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path | |
57 | +# into which the generated documentation will be written. If a relative path is | |
58 | +# entered, it will be relative to the location where doxygen was started. If | |
59 | +# left blank the current directory will be used. | |
60 | + | |
61 | +OUTPUT_DIRECTORY = | |
62 | + | |
63 | +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- | |
64 | +# directories (in 2 levels) under the output directory of each output format and | |
65 | +# will distribute the generated files over these directories. Enabling this | |
66 | +# option can be useful when feeding doxygen a huge amount of source files, where | |
67 | +# putting all generated files in the same directory would otherwise causes | |
68 | +# performance problems for the file system. | |
69 | +# The default value is: NO. | |
70 | + | |
71 | +CREATE_SUBDIRS = NO | |
72 | + | |
73 | +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII | |
74 | +# characters to appear in the names of generated files. If set to NO, non-ASCII | |
75 | +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode | |
76 | +# U+3044. | |
77 | +# The default value is: NO. | |
78 | + | |
79 | +ALLOW_UNICODE_NAMES = NO | |
80 | + | |
81 | +# The OUTPUT_LANGUAGE tag is used to specify the language in which all | |
82 | +# documentation generated by doxygen is written. Doxygen will use this | |
83 | +# information to generate all constant output in the proper language. | |
84 | +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, | |
85 | +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), | |
86 | +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, | |
87 | +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), | |
88 | +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, | |
89 | +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, | |
90 | +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, | |
91 | +# Ukrainian and Vietnamese. | |
92 | +# The default value is: English. | |
93 | + | |
94 | +OUTPUT_LANGUAGE = English | |
95 | + | |
96 | +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member | |
97 | +# descriptions after the members that are listed in the file and class | |
98 | +# documentation (similar to Javadoc). Set to NO to disable this. | |
99 | +# The default value is: YES. | |
100 | + | |
101 | +BRIEF_MEMBER_DESC = YES | |
102 | + | |
103 | +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief | |
104 | +# description of a member or function before the detailed description | |
105 | +# | |
106 | +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the | |
107 | +# brief descriptions will be completely suppressed. | |
108 | +# The default value is: YES. | |
109 | + | |
110 | +REPEAT_BRIEF = YES | |
111 | + | |
112 | +# This tag implements a quasi-intelligent brief description abbreviator that is | |
113 | +# used to form the text in various listings. Each string in this list, if found | |
114 | +# as the leading text of the brief description, will be stripped from the text | |
115 | +# and the result, after processing the whole list, is used as the annotated | |
116 | +# text. Otherwise, the brief description is used as-is. If left blank, the | |
117 | +# following values are used ($name is automatically replaced with the name of | |
118 | +# the entity):The $name class, The $name widget, The $name file, is, provides, | |
119 | +# specifies, contains, represents, a, an and the. | |
120 | + | |
121 | +ABBREVIATE_BRIEF = | |
122 | + | |
123 | +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then | |
124 | +# doxygen will generate a detailed section even if there is only a brief | |
125 | +# description. | |
126 | +# The default value is: NO. | |
127 | + | |
128 | +ALWAYS_DETAILED_SEC = NO | |
129 | + | |
130 | +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all | |
131 | +# inherited members of a class in the documentation of that class as if those | |
132 | +# members were ordinary class members. Constructors, destructors and assignment | |
133 | +# operators of the base classes will not be shown. | |
134 | +# The default value is: NO. | |
135 | + | |
136 | +INLINE_INHERITED_MEMB = NO | |
137 | + | |
138 | +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path | |
139 | +# before files name in the file list and in the header files. If set to NO the | |
140 | +# shortest path that makes the file name unique will be used | |
141 | +# The default value is: YES. | |
142 | + | |
143 | +FULL_PATH_NAMES = YES | |
144 | + | |
145 | +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. | |
146 | +# Stripping is only done if one of the specified strings matches the left-hand | |
147 | +# part of the path. The tag can be used to show relative paths in the file list. | |
148 | +# If left blank the directory from which doxygen is run is used as the path to | |
149 | +# strip. | |
150 | +# | |
151 | +# Note that you can specify absolute paths here, but also relative paths, which | |
152 | +# will be relative from the directory where doxygen is started. | |
153 | +# This tag requires that the tag FULL_PATH_NAMES is set to YES. | |
154 | + | |
155 | +STRIP_FROM_PATH = | |
156 | + | |
157 | +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the | |
158 | +# path mentioned in the documentation of a class, which tells the reader which | |
159 | +# header file to include in order to use a class. If left blank only the name of | |
160 | +# the header file containing the class definition is used. Otherwise one should | |
161 | +# specify the list of include paths that are normally passed to the compiler | |
162 | +# using the -I flag. | |
163 | + | |
164 | +STRIP_FROM_INC_PATH = | |
165 | + | |
166 | +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but | |
167 | +# less readable) file names. This can be useful is your file systems doesn't | |
168 | +# support long names like on DOS, Mac, or CD-ROM. | |
169 | +# The default value is: NO. | |
170 | + | |
171 | +SHORT_NAMES = NO | |
172 | + | |
173 | +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the | |
174 | +# first line (until the first dot) of a Javadoc-style comment as the brief | |
175 | +# description. If set to NO, the Javadoc-style will behave just like regular Qt- | |
176 | +# style comments (thus requiring an explicit @brief command for a brief | |
177 | +# description.) | |
178 | +# The default value is: NO. | |
179 | + | |
180 | +JAVADOC_AUTOBRIEF = NO | |
181 | + | |
182 | +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first | |
183 | +# line (until the first dot) of a Qt-style comment as the brief description. If | |
184 | +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus | |
185 | +# requiring an explicit \brief command for a brief description.) | |
186 | +# The default value is: NO. | |
187 | + | |
188 | +QT_AUTOBRIEF = NO | |
189 | + | |
190 | +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a | |
191 | +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as | |
192 | +# a brief description. This used to be the default behavior. The new default is | |
193 | +# to treat a multi-line C++ comment block as a detailed description. Set this | |
194 | +# tag to YES if you prefer the old behavior instead. | |
195 | +# | |
196 | +# Note that setting this tag to YES also means that rational rose comments are | |
197 | +# not recognized any more. | |
198 | +# The default value is: NO. | |
199 | + | |
200 | +MULTILINE_CPP_IS_BRIEF = NO | |
201 | + | |
202 | +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the | |
203 | +# documentation from any documented member that it re-implements. | |
204 | +# The default value is: YES. | |
205 | + | |
206 | +INHERIT_DOCS = YES | |
207 | + | |
208 | +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new | |
209 | +# page for each member. If set to NO, the documentation of a member will be part | |
210 | +# of the file/class/namespace that contains it. | |
211 | +# The default value is: NO. | |
212 | + | |
213 | +SEPARATE_MEMBER_PAGES = NO | |
214 | + | |
215 | +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen | |
216 | +# uses this value to replace tabs by spaces in code fragments. | |
217 | +# Minimum value: 1, maximum value: 16, default value: 4. | |
218 | + | |
219 | +TAB_SIZE = 4 | |
220 | + | |
221 | +# This tag can be used to specify a number of aliases that act as commands in | |
222 | +# the documentation. An alias has the form: | |
223 | +# name=value | |
224 | +# For example adding | |
225 | +# "sideeffect=@par Side Effects:\n" | |
226 | +# will allow you to put the command \sideeffect (or @sideeffect) in the | |
227 | +# documentation, which will result in a user-defined paragraph with heading | |
228 | +# "Side Effects:". You can put \n's in the value part of an alias to insert | |
229 | +# newlines. | |
230 | + | |
231 | +ALIASES = | |
232 | + | |
233 | +# This tag can be used to specify a number of word-keyword mappings (TCL only). | |
234 | +# A mapping has the form "name=value". For example adding "class=itcl::class" | |
235 | +# will allow you to use the command class in the itcl::class meaning. | |
236 | + | |
237 | +TCL_SUBST = | |
238 | + | |
239 | +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources | |
240 | +# only. Doxygen will then generate output that is more tailored for C. For | |
241 | +# instance, some of the names that are used will be different. The list of all | |
242 | +# members will be omitted, etc. | |
243 | +# The default value is: NO. | |
244 | + | |
245 | +OPTIMIZE_OUTPUT_FOR_C = NO | |
246 | + | |
247 | +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or | |
248 | +# Python sources only. Doxygen will then generate output that is more tailored | |
249 | +# for that language. For instance, namespaces will be presented as packages, | |
250 | +# qualified scopes will look different, etc. | |
251 | +# The default value is: NO. | |
252 | + | |
253 | +OPTIMIZE_OUTPUT_JAVA = NO | |
254 | + | |
255 | +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran | |
256 | +# sources. Doxygen will then generate output that is tailored for Fortran. | |
257 | +# The default value is: NO. | |
258 | + | |
259 | +OPTIMIZE_FOR_FORTRAN = NO | |
260 | + | |
261 | +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL | |
262 | +# sources. Doxygen will then generate output that is tailored for VHDL. | |
263 | +# The default value is: NO. | |
264 | + | |
265 | +OPTIMIZE_OUTPUT_VHDL = NO | |
266 | + | |
267 | +# Doxygen selects the parser to use depending on the extension of the files it | |
268 | +# parses. With this tag you can assign which parser to use for a given | |
269 | +# extension. Doxygen has a built-in mapping, but you can override or extend it | |
270 | +# using this tag. The format is ext=language, where ext is a file extension, and | |
271 | +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, | |
272 | +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: | |
273 | +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: | |
274 | +# Fortran. In the later case the parser tries to guess whether the code is fixed | |
275 | +# or free formatted code, this is the default for Fortran type files), VHDL. For | |
276 | +# instance to make doxygen treat .inc files as Fortran files (default is PHP), | |
277 | +# and .f files as C (default is Fortran), use: inc=Fortran f=C. | |
278 | +# | |
279 | +# Note: For files without extension you can use no_extension as a placeholder. | |
280 | +# | |
281 | +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise | |
282 | +# the files are not read by doxygen. | |
283 | + | |
284 | +EXTENSION_MAPPING = | |
285 | + | |
286 | +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments | |
287 | +# according to the Markdown format, which allows for more readable | |
288 | +# documentation. See http://daringfireball.net/projects/markdown/ for details. | |
289 | +# The output of markdown processing is further processed by doxygen, so you can | |
290 | +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in | |
291 | +# case of backward compatibilities issues. | |
292 | +# The default value is: YES. | |
293 | + | |
294 | +MARKDOWN_SUPPORT = YES | |
295 | + | |
296 | +# When enabled doxygen tries to link words that correspond to documented | |
297 | +# classes, or namespaces to their corresponding documentation. Such a link can | |
298 | +# be prevented in individual cases by putting a % sign in front of the word or | |
299 | +# globally by setting AUTOLINK_SUPPORT to NO. | |
300 | +# The default value is: YES. | |
301 | + | |
302 | +AUTOLINK_SUPPORT = YES | |
303 | + | |
304 | +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want | |
305 | +# to include (a tag file for) the STL sources as input, then you should set this | |
306 | +# tag to YES in order to let doxygen match functions declarations and | |
307 | +# definitions whose arguments contain STL classes (e.g. func(std::string); | |
308 | +# versus func(std::string) {}). This also make the inheritance and collaboration | |
309 | +# diagrams that involve STL classes more complete and accurate. | |
310 | +# The default value is: NO. | |
311 | + | |
312 | +BUILTIN_STL_SUPPORT = NO | |
313 | + | |
314 | +# If you use Microsoft's C++/CLI language, you should set this option to YES to | |
315 | +# enable parsing support. | |
316 | +# The default value is: NO. | |
317 | + | |
318 | +CPP_CLI_SUPPORT = NO | |
319 | + | |
320 | +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: | |
321 | +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen | |
322 | +# will parse them like normal C++ but will assume all classes use public instead | |
323 | +# of private inheritance when no explicit protection keyword is present. | |
324 | +# The default value is: NO. | |
325 | + | |
326 | +SIP_SUPPORT = NO | |
327 | + | |
328 | +# For Microsoft's IDL there are propget and propput attributes to indicate | |
329 | +# getter and setter methods for a property. Setting this option to YES will make | |
330 | +# doxygen to replace the get and set methods by a property in the documentation. | |
331 | +# This will only work if the methods are indeed getting or setting a simple | |
332 | +# type. If this is not the case, or you want to show the methods anyway, you | |
333 | +# should set this option to NO. | |
334 | +# The default value is: YES. | |
335 | + | |
336 | +IDL_PROPERTY_SUPPORT = YES | |
337 | + | |
338 | +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC | |
339 | +# tag is set to YES then doxygen will reuse the documentation of the first | |
340 | +# member in the group (if any) for the other members of the group. By default | |
341 | +# all members of a group must be documented explicitly. | |
342 | +# The default value is: NO. | |
343 | + | |
344 | +DISTRIBUTE_GROUP_DOC = NO | |
345 | + | |
346 | +# Set the SUBGROUPING tag to YES to allow class member groups of the same type | |
347 | +# (for instance a group of public functions) to be put as a subgroup of that | |
348 | +# type (e.g. under the Public Functions section). Set it to NO to prevent | |
349 | +# subgrouping. Alternatively, this can be done per class using the | |
350 | +# \nosubgrouping command. | |
351 | +# The default value is: YES. | |
352 | + | |
353 | +SUBGROUPING = YES | |
354 | + | |
355 | +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions | |
356 | +# are shown inside the group in which they are included (e.g. using \ingroup) | |
357 | +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX | |
358 | +# and RTF). | |
359 | +# | |
360 | +# Note that this feature does not work in combination with | |
361 | +# SEPARATE_MEMBER_PAGES. | |
362 | +# The default value is: NO. | |
363 | + | |
364 | +INLINE_GROUPED_CLASSES = NO | |
365 | + | |
366 | +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions | |
367 | +# with only public data fields or simple typedef fields will be shown inline in | |
368 | +# the documentation of the scope in which they are defined (i.e. file, | |
369 | +# namespace, or group documentation), provided this scope is documented. If set | |
370 | +# to NO, structs, classes, and unions are shown on a separate page (for HTML and | |
371 | +# Man pages) or section (for LaTeX and RTF). | |
372 | +# The default value is: NO. | |
373 | + | |
374 | +INLINE_SIMPLE_STRUCTS = NO | |
375 | + | |
376 | +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or | |
377 | +# enum is documented as struct, union, or enum with the name of the typedef. So | |
378 | +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct | |
379 | +# with name TypeT. When disabled the typedef will appear as a member of a file, | |
380 | +# namespace, or class. And the struct will be named TypeS. This can typically be | |
381 | +# useful for C code in case the coding convention dictates that all compound | |
382 | +# types are typedef'ed and only the typedef is referenced, never the tag name. | |
383 | +# The default value is: NO. | |
384 | + | |
385 | +TYPEDEF_HIDES_STRUCT = NO | |
386 | + | |
387 | +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This | |
388 | +# cache is used to resolve symbols given their name and scope. Since this can be | |
389 | +# an expensive process and often the same symbol appears multiple times in the | |
390 | +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small | |
391 | +# doxygen will become slower. If the cache is too large, memory is wasted. The | |
392 | +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range | |
393 | +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 | |
394 | +# symbols. At the end of a run doxygen will report the cache usage and suggest | |
395 | +# the optimal cache size from a speed point of view. | |
396 | +# Minimum value: 0, maximum value: 9, default value: 0. | |
397 | + | |
398 | +LOOKUP_CACHE_SIZE = 0 | |
399 | + | |
400 | +#--------------------------------------------------------------------------- | |
401 | +# Build related configuration options | |
402 | +#--------------------------------------------------------------------------- | |
403 | + | |
404 | +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in | |
405 | +# documentation are documented, even if no documentation was available. Private | |
406 | +# class members and static file members will be hidden unless the | |
407 | +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. | |
408 | +# Note: This will also disable the warnings about undocumented members that are | |
409 | +# normally produced when WARNINGS is set to YES. | |
410 | +# The default value is: NO. | |
411 | + | |
412 | +EXTRACT_ALL = NO | |
413 | + | |
414 | +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will | |
415 | +# be included in the documentation. | |
416 | +# The default value is: NO. | |
417 | + | |
418 | +EXTRACT_PRIVATE = NO | |
419 | + | |
420 | +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal | |
421 | +# scope will be included in the documentation. | |
422 | +# The default value is: NO. | |
423 | + | |
424 | +EXTRACT_PACKAGE = NO | |
425 | + | |
426 | +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be | |
427 | +# included in the documentation. | |
428 | +# The default value is: NO. | |
429 | + | |
430 | +EXTRACT_STATIC = NO | |
431 | + | |
432 | +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined | |
433 | +# locally in source files will be included in the documentation. If set to NO, | |
434 | +# only classes defined in header files are included. Does not have any effect | |
435 | +# for Java sources. | |
436 | +# The default value is: YES. | |
437 | + | |
438 | +EXTRACT_LOCAL_CLASSES = YES | |
439 | + | |
440 | +# This flag is only useful for Objective-C code. If set to YES, local methods, | |
441 | +# which are defined in the implementation section but not in the interface are | |
442 | +# included in the documentation. If set to NO, only methods in the interface are | |
443 | +# included. | |
444 | +# The default value is: NO. | |
445 | + | |
446 | +EXTRACT_LOCAL_METHODS = NO | |
447 | + | |
448 | +# If this flag is set to YES, the members of anonymous namespaces will be | |
449 | +# extracted and appear in the documentation as a namespace called | |
450 | +# 'anonymous_namespace{file}', where file will be replaced with the base name of | |
451 | +# the file that contains the anonymous namespace. By default anonymous namespace | |
452 | +# are hidden. | |
453 | +# The default value is: NO. | |
454 | + | |
455 | +EXTRACT_ANON_NSPACES = NO | |
456 | + | |
457 | +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all | |
458 | +# undocumented members inside documented classes or files. If set to NO these | |
459 | +# members will be included in the various overviews, but no documentation | |
460 | +# section is generated. This option has no effect if EXTRACT_ALL is enabled. | |
461 | +# The default value is: NO. | |
462 | + | |
463 | +HIDE_UNDOC_MEMBERS = NO | |
464 | + | |
465 | +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all | |
466 | +# undocumented classes that are normally visible in the class hierarchy. If set | |
467 | +# to NO, these classes will be included in the various overviews. This option | |
468 | +# has no effect if EXTRACT_ALL is enabled. | |
469 | +# The default value is: NO. | |
470 | + | |
471 | +HIDE_UNDOC_CLASSES = NO | |
472 | + | |
473 | +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend | |
474 | +# (class|struct|union) declarations. If set to NO, these declarations will be | |
475 | +# included in the documentation. | |
476 | +# The default value is: NO. | |
477 | + | |
478 | +HIDE_FRIEND_COMPOUNDS = NO | |
479 | + | |
480 | +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any | |
481 | +# documentation blocks found inside the body of a function. If set to NO, these | |
482 | +# blocks will be appended to the function's detailed documentation block. | |
483 | +# The default value is: NO. | |
484 | + | |
485 | +HIDE_IN_BODY_DOCS = NO | |
486 | + | |
487 | +# The INTERNAL_DOCS tag determines if documentation that is typed after a | |
488 | +# \internal command is included. If the tag is set to NO then the documentation | |
489 | +# will be excluded. Set it to YES to include the internal documentation. | |
490 | +# The default value is: NO. | |
491 | + | |
492 | +INTERNAL_DOCS = NO | |
493 | + | |
494 | +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file | |
495 | +# names in lower-case letters. If set to YES, upper-case letters are also | |
496 | +# allowed. This is useful if you have classes or files whose names only differ | |
497 | +# in case and if your file system supports case sensitive file names. Windows | |
498 | +# and Mac users are advised to set this option to NO. | |
499 | +# The default value is: system dependent. | |
500 | + | |
501 | +CASE_SENSE_NAMES = NO | |
502 | + | |
503 | +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with | |
504 | +# their full class and namespace scopes in the documentation. If set to YES, the | |
505 | +# scope will be hidden. | |
506 | +# The default value is: NO. | |
507 | + | |
508 | +HIDE_SCOPE_NAMES = NO | |
509 | + | |
510 | +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will | |
511 | +# append additional text to a page's title, such as Class Reference. If set to | |
512 | +# YES the compound reference will be hidden. | |
513 | +# The default value is: NO. | |
514 | + | |
515 | +HIDE_COMPOUND_REFERENCE= NO | |
516 | + | |
517 | +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of | |
518 | +# the files that are included by a file in the documentation of that file. | |
519 | +# The default value is: YES. | |
520 | + | |
521 | +SHOW_INCLUDE_FILES = YES | |
522 | + | |
523 | +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each | |
524 | +# grouped member an include statement to the documentation, telling the reader | |
525 | +# which file to include in order to use the member. | |
526 | +# The default value is: NO. | |
527 | + | |
528 | +SHOW_GROUPED_MEMB_INC = NO | |
529 | + | |
530 | +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include | |
531 | +# files with double quotes in the documentation rather than with sharp brackets. | |
532 | +# The default value is: NO. | |
533 | + | |
534 | +FORCE_LOCAL_INCLUDES = NO | |
535 | + | |
536 | +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the | |
537 | +# documentation for inline members. | |
538 | +# The default value is: YES. | |
539 | + | |
540 | +INLINE_INFO = YES | |
541 | + | |
542 | +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the | |
543 | +# (detailed) documentation of file and class members alphabetically by member | |
544 | +# name. If set to NO, the members will appear in declaration order. | |
545 | +# The default value is: YES. | |
546 | + | |
547 | +SORT_MEMBER_DOCS = YES | |
548 | + | |
549 | +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief | |
550 | +# descriptions of file, namespace and class members alphabetically by member | |
551 | +# name. If set to NO, the members will appear in declaration order. Note that | |
552 | +# this will also influence the order of the classes in the class list. | |
553 | +# The default value is: NO. | |
554 | + | |
555 | +SORT_BRIEF_DOCS = NO | |
556 | + | |
557 | +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the | |
558 | +# (brief and detailed) documentation of class members so that constructors and | |
559 | +# destructors are listed first. If set to NO the constructors will appear in the | |
560 | +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. | |
561 | +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief | |
562 | +# member documentation. | |
563 | +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting | |
564 | +# detailed member documentation. | |
565 | +# The default value is: NO. | |
566 | + | |
567 | +SORT_MEMBERS_CTORS_1ST = NO | |
568 | + | |
569 | +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy | |
570 | +# of group names into alphabetical order. If set to NO the group names will | |
571 | +# appear in their defined order. | |
572 | +# The default value is: NO. | |
573 | + | |
574 | +SORT_GROUP_NAMES = NO | |
575 | + | |
576 | +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by | |
577 | +# fully-qualified names, including namespaces. If set to NO, the class list will | |
578 | +# be sorted only by class name, not including the namespace part. | |
579 | +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. | |
580 | +# Note: This option applies only to the class list, not to the alphabetical | |
581 | +# list. | |
582 | +# The default value is: NO. | |
583 | + | |
584 | +SORT_BY_SCOPE_NAME = NO | |
585 | + | |
586 | +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper | |
587 | +# type resolution of all parameters of a function it will reject a match between | |
588 | +# the prototype and the implementation of a member function even if there is | |
589 | +# only one candidate or it is obvious which candidate to choose by doing a | |
590 | +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still | |
591 | +# accept a match between prototype and implementation in such cases. | |
592 | +# The default value is: NO. | |
593 | + | |
594 | +STRICT_PROTO_MATCHING = NO | |
595 | + | |
596 | +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo | |
597 | +# list. This list is created by putting \todo commands in the documentation. | |
598 | +# The default value is: YES. | |
599 | + | |
600 | +GENERATE_TODOLIST = YES | |
601 | + | |
602 | +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test | |
603 | +# list. This list is created by putting \test commands in the documentation. | |
604 | +# The default value is: YES. | |
605 | + | |
606 | +GENERATE_TESTLIST = YES | |
607 | + | |
608 | +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug | |
609 | +# list. This list is created by putting \bug commands in the documentation. | |
610 | +# The default value is: YES. | |
611 | + | |
612 | +GENERATE_BUGLIST = YES | |
613 | + | |
614 | +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) | |
615 | +# the deprecated list. This list is created by putting \deprecated commands in | |
616 | +# the documentation. | |
617 | +# The default value is: YES. | |
618 | + | |
619 | +GENERATE_DEPRECATEDLIST= YES | |
620 | + | |
621 | +# The ENABLED_SECTIONS tag can be used to enable conditional documentation | |
622 | +# sections, marked by \if <section_label> ... \endif and \cond <section_label> | |
623 | +# ... \endcond blocks. | |
624 | + | |
625 | +ENABLED_SECTIONS = | |
626 | + | |
627 | +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the | |
628 | +# initial value of a variable or macro / define can have for it to appear in the | |
629 | +# documentation. If the initializer consists of more lines than specified here | |
630 | +# it will be hidden. Use a value of 0 to hide initializers completely. The | |
631 | +# appearance of the value of individual variables and macros / defines can be | |
632 | +# controlled using \showinitializer or \hideinitializer command in the | |
633 | +# documentation regardless of this setting. | |
634 | +# Minimum value: 0, maximum value: 10000, default value: 30. | |
635 | + | |
636 | +MAX_INITIALIZER_LINES = 30 | |
637 | + | |
638 | +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at | |
639 | +# the bottom of the documentation of classes and structs. If set to YES, the | |
640 | +# list will mention the files that were used to generate the documentation. | |
641 | +# The default value is: YES. | |
642 | + | |
643 | +SHOW_USED_FILES = YES | |
644 | + | |
645 | +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This | |
646 | +# will remove the Files entry from the Quick Index and from the Folder Tree View | |
647 | +# (if specified). | |
648 | +# The default value is: YES. | |
649 | + | |
650 | +SHOW_FILES = YES | |
651 | + | |
652 | +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces | |
653 | +# page. This will remove the Namespaces entry from the Quick Index and from the | |
654 | +# Folder Tree View (if specified). | |
655 | +# The default value is: YES. | |
656 | + | |
657 | +SHOW_NAMESPACES = YES | |
658 | + | |
659 | +# The FILE_VERSION_FILTER tag can be used to specify a program or script that | |
660 | +# doxygen should invoke to get the current version for each file (typically from | |
661 | +# the version control system). Doxygen will invoke the program by executing (via | |
662 | +# popen()) the command command input-file, where command is the value of the | |
663 | +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided | |
664 | +# by doxygen. Whatever the program writes to standard output is used as the file | |
665 | +# version. For an example see the documentation. | |
666 | + | |
667 | +FILE_VERSION_FILTER = | |
668 | + | |
669 | +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed | |
670 | +# by doxygen. The layout file controls the global structure of the generated | |
671 | +# output files in an output format independent way. To create the layout file | |
672 | +# that represents doxygen's defaults, run doxygen with the -l option. You can | |
673 | +# optionally specify a file name after the option, if omitted DoxygenLayout.xml | |
674 | +# will be used as the name of the layout file. | |
675 | +# | |
676 | +# Note that if you run doxygen from a directory containing a file called | |
677 | +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE | |
678 | +# tag is left empty. | |
679 | + | |
680 | +LAYOUT_FILE = | |
681 | + | |
682 | +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing | |
683 | +# the reference definitions. This must be a list of .bib files. The .bib | |
684 | +# extension is automatically appended if omitted. This requires the bibtex tool | |
685 | +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. | |
686 | +# For LaTeX the style of the bibliography can be controlled using | |
687 | +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the | |
688 | +# search path. See also \cite for info how to create references. | |
689 | + | |
690 | +CITE_BIB_FILES = | |
691 | + | |
692 | +#--------------------------------------------------------------------------- | |
693 | +# Configuration options related to warning and progress messages | |
694 | +#--------------------------------------------------------------------------- | |
695 | + | |
696 | +# The QUIET tag can be used to turn on/off the messages that are generated to | |
697 | +# standard output by doxygen. If QUIET is set to YES this implies that the | |
698 | +# messages are off. | |
699 | +# The default value is: NO. | |
700 | + | |
701 | +QUIET = NO | |
702 | + | |
703 | +# The WARNINGS tag can be used to turn on/off the warning messages that are | |
704 | +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES | |
705 | +# this implies that the warnings are on. | |
706 | +# | |
707 | +# Tip: Turn warnings on while writing the documentation. | |
708 | +# The default value is: YES. | |
709 | + | |
710 | +WARNINGS = YES | |
711 | + | |
712 | +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate | |
713 | +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag | |
714 | +# will automatically be disabled. | |
715 | +# The default value is: YES. | |
716 | + | |
717 | +WARN_IF_UNDOCUMENTED = YES | |
718 | + | |
719 | +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for | |
720 | +# potential errors in the documentation, such as not documenting some parameters | |
721 | +# in a documented function, or documenting parameters that don't exist or using | |
722 | +# markup commands wrongly. | |
723 | +# The default value is: YES. | |
724 | + | |
725 | +WARN_IF_DOC_ERROR = YES | |
726 | + | |
727 | +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that | |
728 | +# are documented, but have no documentation for their parameters or return | |
729 | +# value. If set to NO, doxygen will only warn about wrong or incomplete | |
730 | +# parameter documentation, but not about the absence of documentation. | |
731 | +# The default value is: NO. | |
732 | + | |
733 | +WARN_NO_PARAMDOC = NO | |
734 | + | |
735 | +# The WARN_FORMAT tag determines the format of the warning messages that doxygen | |
736 | +# can produce. The string should contain the $file, $line, and $text tags, which | |
737 | +# will be replaced by the file and line number from which the warning originated | |
738 | +# and the warning text. Optionally the format may contain $version, which will | |
739 | +# be replaced by the version of the file (if it could be obtained via | |
740 | +# FILE_VERSION_FILTER) | |
741 | +# The default value is: $file:$line: $text. | |
742 | + | |
743 | +WARN_FORMAT = "$file:$line: $text" | |
744 | + | |
745 | +# The WARN_LOGFILE tag can be used to specify a file to which warning and error | |
746 | +# messages should be written. If left blank the output is written to standard | |
747 | +# error (stderr). | |
748 | + | |
749 | +WARN_LOGFILE = | |
750 | + | |
751 | +#--------------------------------------------------------------------------- | |
752 | +# Configuration options related to the input files | |
753 | +#--------------------------------------------------------------------------- | |
754 | + | |
755 | +# The INPUT tag is used to specify the files and/or directories that contain | |
756 | +# documented source files. You may enter file names like myfile.cpp or | |
757 | +# directories like /usr/src/myproject. Separate the files or directories with | |
758 | +# spaces. | |
759 | +# Note: If this tag is empty the current directory is searched. | |
760 | + | |
761 | +INPUT = | |
762 | + | |
763 | +# This tag can be used to specify the character encoding of the source files | |
764 | +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses | |
765 | +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv | |
766 | +# documentation (see: http://www.gnu.org/software/libiconv) for the list of | |
767 | +# possible encodings. | |
768 | +# The default value is: UTF-8. | |
769 | + | |
770 | +INPUT_ENCODING = UTF-8 | |
771 | + | |
772 | +# If the value of the INPUT tag contains directories, you can use the | |
773 | +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and | |
774 | +# *.h) to filter out the source-files in the directories. If left blank the | |
775 | +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, | |
776 | +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, | |
777 | +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, | |
778 | +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, | |
779 | +# *.qsf, *.as and *.js. | |
780 | + | |
781 | +FILE_PATTERNS = | |
782 | + | |
783 | +# The RECURSIVE tag can be used to specify whether or not subdirectories should | |
784 | +# be searched for input files as well. | |
785 | +# The default value is: NO. | |
786 | + | |
787 | +RECURSIVE = YES | |
788 | + | |
789 | +# The EXCLUDE tag can be used to specify files and/or directories that should be | |
790 | +# excluded from the INPUT source files. This way you can easily exclude a | |
791 | +# subdirectory from a directory tree whose root is specified with the INPUT tag. | |
792 | +# | |
793 | +# Note that relative paths are relative to the directory from which doxygen is | |
794 | +# run. | |
795 | + | |
796 | +EXCLUDE = | |
797 | + | |
798 | +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or | |
799 | +# directories that are symbolic links (a Unix file system feature) are excluded | |
800 | +# from the input. | |
801 | +# The default value is: NO. | |
802 | + | |
803 | +EXCLUDE_SYMLINKS = NO | |
804 | + | |
805 | +# If the value of the INPUT tag contains directories, you can use the | |
806 | +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude | |
807 | +# certain files from those directories. | |
808 | +# | |
809 | +# Note that the wildcards are matched against the file with absolute path, so to | |
810 | +# exclude all test directories for example use the pattern */test/* | |
811 | + | |
812 | +EXCLUDE_PATTERNS = CImg.h | |
813 | + | |
814 | +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names | |
815 | +# (namespaces, classes, functions, etc.) that should be excluded from the | |
816 | +# output. The symbol name can be a fully qualified name, a word, or if the | |
817 | +# wildcard * is used, a substring. Examples: ANamespace, AClass, | |
818 | +# AClass::ANamespace, ANamespace::*Test | |
819 | +# | |
820 | +# Note that the wildcards are matched against the file with absolute path, so to | |
821 | +# exclude all test directories use the pattern */test/* | |
822 | + | |
823 | +EXCLUDE_SYMBOLS = | |
824 | + | |
825 | +# The EXAMPLE_PATH tag can be used to specify one or more files or directories | |
826 | +# that contain example code fragments that are included (see the \include | |
827 | +# command). | |
828 | + | |
829 | +EXAMPLE_PATH = | |
830 | + | |
831 | +# If the value of the EXAMPLE_PATH tag contains directories, you can use the | |
832 | +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and | |
833 | +# *.h) to filter out the source-files in the directories. If left blank all | |
834 | +# files are included. | |
835 | + | |
836 | +EXAMPLE_PATTERNS = | |
837 | + | |
838 | +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be | |
839 | +# searched for input files to be used with the \include or \dontinclude commands | |
840 | +# irrespective of the value of the RECURSIVE tag. | |
841 | +# The default value is: NO. | |
842 | + | |
843 | +EXAMPLE_RECURSIVE = NO | |
844 | + | |
845 | +# The IMAGE_PATH tag can be used to specify one or more files or directories | |
846 | +# that contain images that are to be included in the documentation (see the | |
847 | +# \image command). | |
848 | + | |
849 | +IMAGE_PATH = | |
850 | + | |
851 | +# The INPUT_FILTER tag can be used to specify a program that doxygen should | |
852 | +# invoke to filter for each input file. Doxygen will invoke the filter program | |
853 | +# by executing (via popen()) the command: | |
854 | +# | |
855 | +# <filter> <input-file> | |
856 | +# | |
857 | +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the | |
858 | +# name of an input file. Doxygen will then use the output that the filter | |
859 | +# program writes to standard output. If FILTER_PATTERNS is specified, this tag | |
860 | +# will be ignored. | |
861 | +# | |
862 | +# Note that the filter must not add or remove lines; it is applied before the | |
863 | +# code is scanned, but not when the output code is generated. If lines are added | |
864 | +# or removed, the anchors will not be placed correctly. | |
865 | + | |
866 | +INPUT_FILTER = | |
867 | + | |
868 | +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern | |
869 | +# basis. Doxygen will compare the file name with each pattern and apply the | |
870 | +# filter if there is a match. The filters are a list of the form: pattern=filter | |
871 | +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how | |
872 | +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the | |
873 | +# patterns match the file name, INPUT_FILTER is applied. | |
874 | + | |
875 | +FILTER_PATTERNS = | |
876 | + | |
877 | +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using | |
878 | +# INPUT_FILTER) will also be used to filter the input files that are used for | |
879 | +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). | |
880 | +# The default value is: NO. | |
881 | + | |
882 | +FILTER_SOURCE_FILES = NO | |
883 | + | |
884 | +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file | |
885 | +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and | |
886 | +# it is also possible to disable source filtering for a specific pattern using | |
887 | +# *.ext= (so without naming a filter). | |
888 | +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. | |
889 | + | |
890 | +FILTER_SOURCE_PATTERNS = | |
891 | + | |
892 | +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that | |
893 | +# is part of the input, its contents will be placed on the main page | |
894 | +# (index.html). This can be useful if you have a project on for instance GitHub | |
895 | +# and want to reuse the introduction page also for the doxygen output. | |
896 | + | |
897 | +USE_MDFILE_AS_MAINPAGE = | |
898 | + | |
899 | +#--------------------------------------------------------------------------- | |
900 | +# Configuration options related to source browsing | |
901 | +#--------------------------------------------------------------------------- | |
902 | + | |
903 | +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be | |
904 | +# generated. Documented entities will be cross-referenced with these sources. | |
905 | +# | |
906 | +# Note: To get rid of all source code in the generated output, make sure that | |
907 | +# also VERBATIM_HEADERS is set to NO. | |
908 | +# The default value is: NO. | |
909 | + | |
910 | +SOURCE_BROWSER = NO | |
911 | + | |
912 | +# Setting the INLINE_SOURCES tag to YES will include the body of functions, | |
913 | +# classes and enums directly into the documentation. | |
914 | +# The default value is: NO. | |
915 | + | |
916 | +INLINE_SOURCES = NO | |
917 | + | |
918 | +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any | |
919 | +# special comment blocks from generated source code fragments. Normal C, C++ and | |
920 | +# Fortran comments will always remain visible. | |
921 | +# The default value is: YES. | |
922 | + | |
923 | +STRIP_CODE_COMMENTS = YES | |
924 | + | |
925 | +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented | |
926 | +# function all documented functions referencing it will be listed. | |
927 | +# The default value is: NO. | |
928 | + | |
929 | +REFERENCED_BY_RELATION = NO | |
930 | + | |
931 | +# If the REFERENCES_RELATION tag is set to YES then for each documented function | |
932 | +# all documented entities called/used by that function will be listed. | |
933 | +# The default value is: NO. | |
934 | + | |
935 | +REFERENCES_RELATION = NO | |
936 | + | |
937 | +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set | |
938 | +# to YES then the hyperlinks from functions in REFERENCES_RELATION and | |
939 | +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will | |
940 | +# link to the documentation. | |
941 | +# The default value is: YES. | |
942 | + | |
943 | +REFERENCES_LINK_SOURCE = YES | |
944 | + | |
945 | +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the | |
946 | +# source code will show a tooltip with additional information such as prototype, | |
947 | +# brief description and links to the definition and documentation. Since this | |
948 | +# will make the HTML file larger and loading of large files a bit slower, you | |
949 | +# can opt to disable this feature. | |
950 | +# The default value is: YES. | |
951 | +# This tag requires that the tag SOURCE_BROWSER is set to YES. | |
952 | + | |
953 | +SOURCE_TOOLTIPS = YES | |
954 | + | |
955 | +# If the USE_HTAGS tag is set to YES then the references to source code will | |
956 | +# point to the HTML generated by the htags(1) tool instead of doxygen built-in | |
957 | +# source browser. The htags tool is part of GNU's global source tagging system | |
958 | +# (see http://www.gnu.org/software/global/global.html). You will need version | |
959 | +# 4.8.6 or higher. | |
960 | +# | |
961 | +# To use it do the following: | |
962 | +# - Install the latest version of global | |
963 | +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file | |
964 | +# - Make sure the INPUT points to the root of the source tree | |
965 | +# - Run doxygen as normal | |
966 | +# | |
967 | +# Doxygen will invoke htags (and that will in turn invoke gtags), so these | |
968 | +# tools must be available from the command line (i.e. in the search path). | |
969 | +# | |
970 | +# The result: instead of the source browser generated by doxygen, the links to | |
971 | +# source code will now point to the output of htags. | |
972 | +# The default value is: NO. | |
973 | +# This tag requires that the tag SOURCE_BROWSER is set to YES. | |
974 | + | |
975 | +USE_HTAGS = NO | |
976 | + | |
977 | +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a | |
978 | +# verbatim copy of the header file for each class for which an include is | |
979 | +# specified. Set to NO to disable this. | |
980 | +# See also: Section \class. | |
981 | +# The default value is: YES. | |
982 | + | |
983 | +VERBATIM_HEADERS = YES | |
984 | + | |
985 | +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the | |
986 | +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the | |
987 | +# cost of reduced performance. This can be particularly helpful with template | |
988 | +# rich C++ code for which doxygen's built-in parser lacks the necessary type | |
989 | +# information. | |
990 | +# Note: The availability of this option depends on whether or not doxygen was | |
991 | +# compiled with the --with-libclang option. | |
992 | +# The default value is: NO. | |
993 | + | |
994 | +CLANG_ASSISTED_PARSING = NO | |
995 | + | |
996 | +# If clang assisted parsing is enabled you can provide the compiler with command | |
997 | +# line options that you would normally use when invoking the compiler. Note that | |
998 | +# the include paths will already be set by doxygen for the files and directories | |
999 | +# specified with INPUT and INCLUDE_PATH. | |
1000 | +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. | |
1001 | + | |
1002 | +CLANG_OPTIONS = | |
1003 | + | |
1004 | +#--------------------------------------------------------------------------- | |
1005 | +# Configuration options related to the alphabetical class index | |
1006 | +#--------------------------------------------------------------------------- | |
1007 | + | |
1008 | +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all | |
1009 | +# compounds will be generated. Enable this if the project contains a lot of | |
1010 | +# classes, structs, unions or interfaces. | |
1011 | +# The default value is: YES. | |
1012 | + | |
1013 | +ALPHABETICAL_INDEX = YES | |
1014 | + | |
1015 | +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in | |
1016 | +# which the alphabetical index list will be split. | |
1017 | +# Minimum value: 1, maximum value: 20, default value: 5. | |
1018 | +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. | |
1019 | + | |
1020 | +COLS_IN_ALPHA_INDEX = 5 | |
1021 | + | |
1022 | +# In case all classes in a project start with a common prefix, all classes will | |
1023 | +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag | |
1024 | +# can be used to specify a prefix (or a list of prefixes) that should be ignored | |
1025 | +# while generating the index headers. | |
1026 | +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. | |
1027 | + | |
1028 | +IGNORE_PREFIX = | |
1029 | + | |
1030 | +#--------------------------------------------------------------------------- | |
1031 | +# Configuration options related to the HTML output | |
1032 | +#--------------------------------------------------------------------------- | |
1033 | + | |
1034 | +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output | |
1035 | +# The default value is: YES. | |
1036 | + | |
1037 | +GENERATE_HTML = YES | |
1038 | + | |
1039 | +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a | |
1040 | +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of | |
1041 | +# it. | |
1042 | +# The default directory is: html. | |
1043 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1044 | + | |
1045 | +HTML_OUTPUT = html | |
1046 | + | |
1047 | +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each | |
1048 | +# generated HTML page (for example: .htm, .php, .asp). | |
1049 | +# The default value is: .html. | |
1050 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1051 | + | |
1052 | +HTML_FILE_EXTENSION = .html | |
1053 | + | |
1054 | +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for | |
1055 | +# each generated HTML page. If the tag is left blank doxygen will generate a | |
1056 | +# standard header. | |
1057 | +# | |
1058 | +# To get valid HTML the header file that includes any scripts and style sheets | |
1059 | +# that doxygen needs, which is dependent on the configuration options used (e.g. | |
1060 | +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a | |
1061 | +# default header using | |
1062 | +# doxygen -w html new_header.html new_footer.html new_stylesheet.css | |
1063 | +# YourConfigFile | |
1064 | +# and then modify the file new_header.html. See also section "Doxygen usage" | |
1065 | +# for information on how to generate the default header that doxygen normally | |
1066 | +# uses. | |
1067 | +# Note: The header is subject to change so you typically have to regenerate the | |
1068 | +# default header when upgrading to a newer version of doxygen. For a description | |
1069 | +# of the possible markers and block names see the documentation. | |
1070 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1071 | + | |
1072 | +HTML_HEADER = | |
1073 | + | |
1074 | +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each | |
1075 | +# generated HTML page. If the tag is left blank doxygen will generate a standard | |
1076 | +# footer. See HTML_HEADER for more information on how to generate a default | |
1077 | +# footer and what special commands can be used inside the footer. See also | |
1078 | +# section "Doxygen usage" for information on how to generate the default footer | |
1079 | +# that doxygen normally uses. | |
1080 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1081 | + | |
1082 | +HTML_FOOTER = | |
1083 | + | |
1084 | +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style | |
1085 | +# sheet that is used by each HTML page. It can be used to fine-tune the look of | |
1086 | +# the HTML output. If left blank doxygen will generate a default style sheet. | |
1087 | +# See also section "Doxygen usage" for information on how to generate the style | |
1088 | +# sheet that doxygen normally uses. | |
1089 | +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as | |
1090 | +# it is more robust and this tag (HTML_STYLESHEET) will in the future become | |
1091 | +# obsolete. | |
1092 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1093 | + | |
1094 | +HTML_STYLESHEET = | |
1095 | + | |
1096 | +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined | |
1097 | +# cascading style sheets that are included after the standard style sheets | |
1098 | +# created by doxygen. Using this option one can overrule certain style aspects. | |
1099 | +# This is preferred over using HTML_STYLESHEET since it does not replace the | |
1100 | +# standard style sheet and is therefore more robust against future updates. | |
1101 | +# Doxygen will copy the style sheet files to the output directory. | |
1102 | +# Note: The order of the extra style sheet files is of importance (e.g. the last | |
1103 | +# style sheet in the list overrules the setting of the previous ones in the | |
1104 | +# list). For an example see the documentation. | |
1105 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1106 | + | |
1107 | +HTML_EXTRA_STYLESHEET = | |
1108 | + | |
1109 | +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or | |
1110 | +# other source files which should be copied to the HTML output directory. Note | |
1111 | +# that these files will be copied to the base HTML output directory. Use the | |
1112 | +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these | |
1113 | +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the | |
1114 | +# files will be copied as-is; there are no commands or markers available. | |
1115 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1116 | + | |
1117 | +HTML_EXTRA_FILES = | |
1118 | + | |
1119 | +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen | |
1120 | +# will adjust the colors in the style sheet and background images according to | |
1121 | +# this color. Hue is specified as an angle on a colorwheel, see | |
1122 | +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value | |
1123 | +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 | |
1124 | +# purple, and 360 is red again. | |
1125 | +# Minimum value: 0, maximum value: 359, default value: 220. | |
1126 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1127 | + | |
1128 | +HTML_COLORSTYLE_HUE = 220 | |
1129 | + | |
1130 | +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors | |
1131 | +# in the HTML output. For a value of 0 the output will use grayscales only. A | |
1132 | +# value of 255 will produce the most vivid colors. | |
1133 | +# Minimum value: 0, maximum value: 255, default value: 100. | |
1134 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1135 | + | |
1136 | +HTML_COLORSTYLE_SAT = 100 | |
1137 | + | |
1138 | +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the | |
1139 | +# luminance component of the colors in the HTML output. Values below 100 | |
1140 | +# gradually make the output lighter, whereas values above 100 make the output | |
1141 | +# darker. The value divided by 100 is the actual gamma applied, so 80 represents | |
1142 | +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not | |
1143 | +# change the gamma. | |
1144 | +# Minimum value: 40, maximum value: 240, default value: 80. | |
1145 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1146 | + | |
1147 | +HTML_COLORSTYLE_GAMMA = 80 | |
1148 | + | |
1149 | +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML | |
1150 | +# page will contain the date and time when the page was generated. Setting this | |
1151 | +# to NO can help when comparing the output of multiple runs. | |
1152 | +# The default value is: YES. | |
1153 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1154 | + | |
1155 | +HTML_TIMESTAMP = YES | |
1156 | + | |
1157 | +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML | |
1158 | +# documentation will contain sections that can be hidden and shown after the | |
1159 | +# page has loaded. | |
1160 | +# The default value is: NO. | |
1161 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1162 | + | |
1163 | +HTML_DYNAMIC_SECTIONS = NO | |
1164 | + | |
1165 | +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries | |
1166 | +# shown in the various tree structured indices initially; the user can expand | |
1167 | +# and collapse entries dynamically later on. Doxygen will expand the tree to | |
1168 | +# such a level that at most the specified number of entries are visible (unless | |
1169 | +# a fully collapsed tree already exceeds this amount). So setting the number of | |
1170 | +# entries 1 will produce a full collapsed tree by default. 0 is a special value | |
1171 | +# representing an infinite number of entries and will result in a full expanded | |
1172 | +# tree by default. | |
1173 | +# Minimum value: 0, maximum value: 9999, default value: 100. | |
1174 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1175 | + | |
1176 | +HTML_INDEX_NUM_ENTRIES = 100 | |
1177 | + | |
1178 | +# If the GENERATE_DOCSET tag is set to YES, additional index files will be | |
1179 | +# generated that can be used as input for Apple's Xcode 3 integrated development | |
1180 | +# environment (see: http://developer.apple.com/tools/xcode/), introduced with | |
1181 | +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a | |
1182 | +# Makefile in the HTML output directory. Running make will produce the docset in | |
1183 | +# that directory and running make install will install the docset in | |
1184 | +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at | |
1185 | +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html | |
1186 | +# for more information. | |
1187 | +# The default value is: NO. | |
1188 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1189 | + | |
1190 | +GENERATE_DOCSET = NO | |
1191 | + | |
1192 | +# This tag determines the name of the docset feed. A documentation feed provides | |
1193 | +# an umbrella under which multiple documentation sets from a single provider | |
1194 | +# (such as a company or product suite) can be grouped. | |
1195 | +# The default value is: Doxygen generated docs. | |
1196 | +# This tag requires that the tag GENERATE_DOCSET is set to YES. | |
1197 | + | |
1198 | +DOCSET_FEEDNAME = "Doxygen generated docs" | |
1199 | + | |
1200 | +# This tag specifies a string that should uniquely identify the documentation | |
1201 | +# set bundle. This should be a reverse domain-name style string, e.g. | |
1202 | +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. | |
1203 | +# The default value is: org.doxygen.Project. | |
1204 | +# This tag requires that the tag GENERATE_DOCSET is set to YES. | |
1205 | + | |
1206 | +DOCSET_BUNDLE_ID = org.doxygen.Project | |
1207 | + | |
1208 | +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify | |
1209 | +# the documentation publisher. This should be a reverse domain-name style | |
1210 | +# string, e.g. com.mycompany.MyDocSet.documentation. | |
1211 | +# The default value is: org.doxygen.Publisher. | |
1212 | +# This tag requires that the tag GENERATE_DOCSET is set to YES. | |
1213 | + | |
1214 | +DOCSET_PUBLISHER_ID = org.doxygen.Publisher | |
1215 | + | |
1216 | +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. | |
1217 | +# The default value is: Publisher. | |
1218 | +# This tag requires that the tag GENERATE_DOCSET is set to YES. | |
1219 | + | |
1220 | +DOCSET_PUBLISHER_NAME = Publisher | |
1221 | + | |
1222 | +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three | |
1223 | +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The | |
1224 | +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop | |
1225 | +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on | |
1226 | +# Windows. | |
1227 | +# | |
1228 | +# The HTML Help Workshop contains a compiler that can convert all HTML output | |
1229 | +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML | |
1230 | +# files are now used as the Windows 98 help format, and will replace the old | |
1231 | +# Windows help format (.hlp) on all Windows platforms in the future. Compressed | |
1232 | +# HTML files also contain an index, a table of contents, and you can search for | |
1233 | +# words in the documentation. The HTML workshop also contains a viewer for | |
1234 | +# compressed HTML files. | |
1235 | +# The default value is: NO. | |
1236 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1237 | + | |
1238 | +GENERATE_HTMLHELP = NO | |
1239 | + | |
1240 | +# The CHM_FILE tag can be used to specify the file name of the resulting .chm | |
1241 | +# file. You can add a path in front of the file if the result should not be | |
1242 | +# written to the html output directory. | |
1243 | +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. | |
1244 | + | |
1245 | +CHM_FILE = | |
1246 | + | |
1247 | +# The HHC_LOCATION tag can be used to specify the location (absolute path | |
1248 | +# including file name) of the HTML help compiler (hhc.exe). If non-empty, | |
1249 | +# doxygen will try to run the HTML help compiler on the generated index.hhp. | |
1250 | +# The file has to be specified with full path. | |
1251 | +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. | |
1252 | + | |
1253 | +HHC_LOCATION = | |
1254 | + | |
1255 | +# The GENERATE_CHI flag controls if a separate .chi index file is generated | |
1256 | +# (YES) or that it should be included in the master .chm file (NO). | |
1257 | +# The default value is: NO. | |
1258 | +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. | |
1259 | + | |
1260 | +GENERATE_CHI = NO | |
1261 | + | |
1262 | +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) | |
1263 | +# and project file content. | |
1264 | +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. | |
1265 | + | |
1266 | +CHM_INDEX_ENCODING = | |
1267 | + | |
1268 | +# The BINARY_TOC flag controls whether a binary table of contents is generated | |
1269 | +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it | |
1270 | +# enables the Previous and Next buttons. | |
1271 | +# The default value is: NO. | |
1272 | +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. | |
1273 | + | |
1274 | +BINARY_TOC = NO | |
1275 | + | |
1276 | +# The TOC_EXPAND flag can be set to YES to add extra items for group members to | |
1277 | +# the table of contents of the HTML help documentation and to the tree view. | |
1278 | +# The default value is: NO. | |
1279 | +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. | |
1280 | + | |
1281 | +TOC_EXPAND = NO | |
1282 | + | |
1283 | +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and | |
1284 | +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that | |
1285 | +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help | |
1286 | +# (.qch) of the generated HTML documentation. | |
1287 | +# The default value is: NO. | |
1288 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1289 | + | |
1290 | +GENERATE_QHP = NO | |
1291 | + | |
1292 | +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify | |
1293 | +# the file name of the resulting .qch file. The path specified is relative to | |
1294 | +# the HTML output folder. | |
1295 | +# This tag requires that the tag GENERATE_QHP is set to YES. | |
1296 | + | |
1297 | +QCH_FILE = | |
1298 | + | |
1299 | +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help | |
1300 | +# Project output. For more information please see Qt Help Project / Namespace | |
1301 | +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). | |
1302 | +# The default value is: org.doxygen.Project. | |
1303 | +# This tag requires that the tag GENERATE_QHP is set to YES. | |
1304 | + | |
1305 | +QHP_NAMESPACE = org.doxygen.Project | |
1306 | + | |
1307 | +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt | |
1308 | +# Help Project output. For more information please see Qt Help Project / Virtual | |
1309 | +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- | |
1310 | +# folders). | |
1311 | +# The default value is: doc. | |
1312 | +# This tag requires that the tag GENERATE_QHP is set to YES. | |
1313 | + | |
1314 | +QHP_VIRTUAL_FOLDER = doc | |
1315 | + | |
1316 | +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom | |
1317 | +# filter to add. For more information please see Qt Help Project / Custom | |
1318 | +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- | |
1319 | +# filters). | |
1320 | +# This tag requires that the tag GENERATE_QHP is set to YES. | |
1321 | + | |
1322 | +QHP_CUST_FILTER_NAME = | |
1323 | + | |
1324 | +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the | |
1325 | +# custom filter to add. For more information please see Qt Help Project / Custom | |
1326 | +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- | |
1327 | +# filters). | |
1328 | +# This tag requires that the tag GENERATE_QHP is set to YES. | |
1329 | + | |
1330 | +QHP_CUST_FILTER_ATTRS = | |
1331 | + | |
1332 | +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this | |
1333 | +# project's filter section matches. Qt Help Project / Filter Attributes (see: | |
1334 | +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). | |
1335 | +# This tag requires that the tag GENERATE_QHP is set to YES. | |
1336 | + | |
1337 | +QHP_SECT_FILTER_ATTRS = | |
1338 | + | |
1339 | +# The QHG_LOCATION tag can be used to specify the location of Qt's | |
1340 | +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the | |
1341 | +# generated .qhp file. | |
1342 | +# This tag requires that the tag GENERATE_QHP is set to YES. | |
1343 | + | |
1344 | +QHG_LOCATION = | |
1345 | + | |
1346 | +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be | |
1347 | +# generated, together with the HTML files, they form an Eclipse help plugin. To | |
1348 | +# install this plugin and make it available under the help contents menu in | |
1349 | +# Eclipse, the contents of the directory containing the HTML and XML files needs | |
1350 | +# to be copied into the plugins directory of eclipse. The name of the directory | |
1351 | +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. | |
1352 | +# After copying Eclipse needs to be restarted before the help appears. | |
1353 | +# The default value is: NO. | |
1354 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1355 | + | |
1356 | +GENERATE_ECLIPSEHELP = NO | |
1357 | + | |
1358 | +# A unique identifier for the Eclipse help plugin. When installing the plugin | |
1359 | +# the directory name containing the HTML and XML files should also have this | |
1360 | +# name. Each documentation set should have its own identifier. | |
1361 | +# The default value is: org.doxygen.Project. | |
1362 | +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. | |
1363 | + | |
1364 | +ECLIPSE_DOC_ID = org.doxygen.Project | |
1365 | + | |
1366 | +# If you want full control over the layout of the generated HTML pages it might | |
1367 | +# be necessary to disable the index and replace it with your own. The | |
1368 | +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top | |
1369 | +# of each HTML page. A value of NO enables the index and the value YES disables | |
1370 | +# it. Since the tabs in the index contain the same information as the navigation | |
1371 | +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. | |
1372 | +# The default value is: NO. | |
1373 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1374 | + | |
1375 | +DISABLE_INDEX = NO | |
1376 | + | |
1377 | +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index | |
1378 | +# structure should be generated to display hierarchical information. If the tag | |
1379 | +# value is set to YES, a side panel will be generated containing a tree-like | |
1380 | +# index structure (just like the one that is generated for HTML Help). For this | |
1381 | +# to work a browser that supports JavaScript, DHTML, CSS and frames is required | |
1382 | +# (i.e. any modern browser). Windows users are probably better off using the | |
1383 | +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can | |
1384 | +# further fine-tune the look of the index. As an example, the default style | |
1385 | +# sheet generated by doxygen has an example that shows how to put an image at | |
1386 | +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has | |
1387 | +# the same information as the tab index, you could consider setting | |
1388 | +# DISABLE_INDEX to YES when enabling this option. | |
1389 | +# The default value is: NO. | |
1390 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1391 | + | |
1392 | +GENERATE_TREEVIEW = NO | |
1393 | + | |
1394 | +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that | |
1395 | +# doxygen will group on one line in the generated HTML documentation. | |
1396 | +# | |
1397 | +# Note that a value of 0 will completely suppress the enum values from appearing | |
1398 | +# in the overview section. | |
1399 | +# Minimum value: 0, maximum value: 20, default value: 4. | |
1400 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1401 | + | |
1402 | +ENUM_VALUES_PER_LINE = 4 | |
1403 | + | |
1404 | +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used | |
1405 | +# to set the initial width (in pixels) of the frame in which the tree is shown. | |
1406 | +# Minimum value: 0, maximum value: 1500, default value: 250. | |
1407 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1408 | + | |
1409 | +TREEVIEW_WIDTH = 250 | |
1410 | + | |
1411 | +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to | |
1412 | +# external symbols imported via tag files in a separate window. | |
1413 | +# The default value is: NO. | |
1414 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1415 | + | |
1416 | +EXT_LINKS_IN_WINDOW = NO | |
1417 | + | |
1418 | +# Use this tag to change the font size of LaTeX formulas included as images in | |
1419 | +# the HTML documentation. When you change the font size after a successful | |
1420 | +# doxygen run you need to manually remove any form_*.png images from the HTML | |
1421 | +# output directory to force them to be regenerated. | |
1422 | +# Minimum value: 8, maximum value: 50, default value: 10. | |
1423 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1424 | + | |
1425 | +FORMULA_FONTSIZE = 10 | |
1426 | + | |
1427 | +# Use the FORMULA_TRANPARENT tag to determine whether or not the images | |
1428 | +# generated for formulas are transparent PNGs. Transparent PNGs are not | |
1429 | +# supported properly for IE 6.0, but are supported on all modern browsers. | |
1430 | +# | |
1431 | +# Note that when changing this option you need to delete any form_*.png files in | |
1432 | +# the HTML output directory before the changes have effect. | |
1433 | +# The default value is: YES. | |
1434 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1435 | + | |
1436 | +FORMULA_TRANSPARENT = YES | |
1437 | + | |
1438 | +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see | |
1439 | +# http://www.mathjax.org) which uses client side Javascript for the rendering | |
1440 | +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX | |
1441 | +# installed or if you want to formulas look prettier in the HTML output. When | |
1442 | +# enabled you may also need to install MathJax separately and configure the path | |
1443 | +# to it using the MATHJAX_RELPATH option. | |
1444 | +# The default value is: NO. | |
1445 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1446 | + | |
1447 | +USE_MATHJAX = NO | |
1448 | + | |
1449 | +# When MathJax is enabled you can set the default output format to be used for | |
1450 | +# the MathJax output. See the MathJax site (see: | |
1451 | +# http://docs.mathjax.org/en/latest/output.html) for more details. | |
1452 | +# Possible values are: HTML-CSS (which is slower, but has the best | |
1453 | +# compatibility), NativeMML (i.e. MathML) and SVG. | |
1454 | +# The default value is: HTML-CSS. | |
1455 | +# This tag requires that the tag USE_MATHJAX is set to YES. | |
1456 | + | |
1457 | +MATHJAX_FORMAT = HTML-CSS | |
1458 | + | |
1459 | +# When MathJax is enabled you need to specify the location relative to the HTML | |
1460 | +# output directory using the MATHJAX_RELPATH option. The destination directory | |
1461 | +# should contain the MathJax.js script. For instance, if the mathjax directory | |
1462 | +# is located at the same level as the HTML output directory, then | |
1463 | +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax | |
1464 | +# Content Delivery Network so you can quickly see the result without installing | |
1465 | +# MathJax. However, it is strongly recommended to install a local copy of | |
1466 | +# MathJax from http://www.mathjax.org before deployment. | |
1467 | +# The default value is: http://cdn.mathjax.org/mathjax/latest. | |
1468 | +# This tag requires that the tag USE_MATHJAX is set to YES. | |
1469 | + | |
1470 | +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest | |
1471 | + | |
1472 | +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax | |
1473 | +# extension names that should be enabled during MathJax rendering. For example | |
1474 | +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols | |
1475 | +# This tag requires that the tag USE_MATHJAX is set to YES. | |
1476 | + | |
1477 | +MATHJAX_EXTENSIONS = | |
1478 | + | |
1479 | +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces | |
1480 | +# of code that will be used on startup of the MathJax code. See the MathJax site | |
1481 | +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an | |
1482 | +# example see the documentation. | |
1483 | +# This tag requires that the tag USE_MATHJAX is set to YES. | |
1484 | + | |
1485 | +MATHJAX_CODEFILE = | |
1486 | + | |
1487 | +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for | |
1488 | +# the HTML output. The underlying search engine uses javascript and DHTML and | |
1489 | +# should work on any modern browser. Note that when using HTML help | |
1490 | +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) | |
1491 | +# there is already a search function so this one should typically be disabled. | |
1492 | +# For large projects the javascript based search engine can be slow, then | |
1493 | +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to | |
1494 | +# search using the keyboard; to jump to the search box use <access key> + S | |
1495 | +# (what the <access key> is depends on the OS and browser, but it is typically | |
1496 | +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down | |
1497 | +# key> to jump into the search results window, the results can be navigated | |
1498 | +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel | |
1499 | +# the search. The filter options can be selected when the cursor is inside the | |
1500 | +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> | |
1501 | +# to select a filter and <Enter> or <escape> to activate or cancel the filter | |
1502 | +# option. | |
1503 | +# The default value is: YES. | |
1504 | +# This tag requires that the tag GENERATE_HTML is set to YES. | |
1505 | + | |
1506 | +SEARCHENGINE = YES | |
1507 | + | |
1508 | +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be | |
1509 | +# implemented using a web server instead of a web client using Javascript. There | |
1510 | +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH | |
1511 | +# setting. When disabled, doxygen will generate a PHP script for searching and | |
1512 | +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing | |
1513 | +# and searching needs to be provided by external tools. See the section | |
1514 | +# "External Indexing and Searching" for details. | |
1515 | +# The default value is: NO. | |
1516 | +# This tag requires that the tag SEARCHENGINE is set to YES. | |
1517 | + | |
1518 | +SERVER_BASED_SEARCH = NO | |
1519 | + | |
1520 | +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP | |
1521 | +# script for searching. Instead the search results are written to an XML file | |
1522 | +# which needs to be processed by an external indexer. Doxygen will invoke an | |
1523 | +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the | |
1524 | +# search results. | |
1525 | +# | |
1526 | +# Doxygen ships with an example indexer (doxyindexer) and search engine | |
1527 | +# (doxysearch.cgi) which are based on the open source search engine library | |
1528 | +# Xapian (see: http://xapian.org/). | |
1529 | +# | |
1530 | +# See the section "External Indexing and Searching" for details. | |
1531 | +# The default value is: NO. | |
1532 | +# This tag requires that the tag SEARCHENGINE is set to YES. | |
1533 | + | |
1534 | +EXTERNAL_SEARCH = NO | |
1535 | + | |
1536 | +# The SEARCHENGINE_URL should point to a search engine hosted by a web server | |
1537 | +# which will return the search results when EXTERNAL_SEARCH is enabled. | |
1538 | +# | |
1539 | +# Doxygen ships with an example indexer (doxyindexer) and search engine | |
1540 | +# (doxysearch.cgi) which are based on the open source search engine library | |
1541 | +# Xapian (see: http://xapian.org/). See the section "External Indexing and | |
1542 | +# Searching" for details. | |
1543 | +# This tag requires that the tag SEARCHENGINE is set to YES. | |
1544 | + | |
1545 | +SEARCHENGINE_URL = | |
1546 | + | |
1547 | +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed | |
1548 | +# search data is written to a file for indexing by an external tool. With the | |
1549 | +# SEARCHDATA_FILE tag the name of this file can be specified. | |
1550 | +# The default file is: searchdata.xml. | |
1551 | +# This tag requires that the tag SEARCHENGINE is set to YES. | |
1552 | + | |
1553 | +SEARCHDATA_FILE = searchdata.xml | |
1554 | + | |
1555 | +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the | |
1556 | +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is | |
1557 | +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple | |
1558 | +# projects and redirect the results back to the right project. | |
1559 | +# This tag requires that the tag SEARCHENGINE is set to YES. | |
1560 | + | |
1561 | +EXTERNAL_SEARCH_ID = | |
1562 | + | |
1563 | +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen | |
1564 | +# projects other than the one defined by this configuration file, but that are | |
1565 | +# all added to the same external search index. Each project needs to have a | |
1566 | +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of | |
1567 | +# to a relative location where the documentation can be found. The format is: | |
1568 | +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... | |
1569 | +# This tag requires that the tag SEARCHENGINE is set to YES. | |
1570 | + | |
1571 | +EXTRA_SEARCH_MAPPINGS = | |
1572 | + | |
1573 | +#--------------------------------------------------------------------------- | |
1574 | +# Configuration options related to the LaTeX output | |
1575 | +#--------------------------------------------------------------------------- | |
1576 | + | |
1577 | +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. | |
1578 | +# The default value is: YES. | |
1579 | + | |
1580 | +GENERATE_LATEX = YES | |
1581 | + | |
1582 | +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a | |
1583 | +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of | |
1584 | +# it. | |
1585 | +# The default directory is: latex. | |
1586 | +# This tag requires that the tag GENERATE_LATEX is set to YES. | |
1587 | + | |
1588 | +LATEX_OUTPUT = latex | |
1589 | + | |
1590 | +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be | |
1591 | +# invoked. | |
1592 | +# | |
1593 | +# Note that when enabling USE_PDFLATEX this option is only used for generating | |
1594 | +# bitmaps for formulas in the HTML output, but not in the Makefile that is | |
1595 | +# written to the output directory. | |
1596 | +# The default file is: latex. | |
1597 | +# This tag requires that the tag GENERATE_LATEX is set to YES. | |
1598 | + | |
1599 | +LATEX_CMD_NAME = latex | |
1600 | + | |
1601 | +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate | |
1602 | +# index for LaTeX. | |
1603 | +# The default file is: makeindex. | |
1604 | +# This tag requires that the tag GENERATE_LATEX is set to YES. | |
1605 | + | |
1606 | +MAKEINDEX_CMD_NAME = makeindex | |
1607 | + | |
1608 | +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX | |
1609 | +# documents. This may be useful for small projects and may help to save some | |
1610 | +# trees in general. | |
1611 | +# The default value is: NO. | |
1612 | +# This tag requires that the tag GENERATE_LATEX is set to YES. | |
1613 | + | |
1614 | +COMPACT_LATEX = NO | |
1615 | + | |
1616 | +# The PAPER_TYPE tag can be used to set the paper type that is used by the | |
1617 | +# printer. | |
1618 | +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x | |
1619 | +# 14 inches) and executive (7.25 x 10.5 inches). | |
1620 | +# The default value is: a4. | |
1621 | +# This tag requires that the tag GENERATE_LATEX is set to YES. | |
1622 | + | |
1623 | +PAPER_TYPE = a4 | |
1624 | + | |
1625 | +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names | |
1626 | +# that should be included in the LaTeX output. To get the times font for | |
1627 | +# instance you can specify | |
1628 | +# EXTRA_PACKAGES=times | |
1629 | +# If left blank no extra packages will be included. | |
1630 | +# This tag requires that the tag GENERATE_LATEX is set to YES. | |
1631 | + | |
1632 | +EXTRA_PACKAGES = | |
1633 | + | |
1634 | +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the | |
1635 | +# generated LaTeX document. The header should contain everything until the first | |
1636 | +# chapter. If it is left blank doxygen will generate a standard header. See | |
1637 | +# section "Doxygen usage" for information on how to let doxygen write the | |
1638 | +# default header to a separate file. | |
1639 | +# | |
1640 | +# Note: Only use a user-defined header if you know what you are doing! The | |
1641 | +# following commands have a special meaning inside the header: $title, | |
1642 | +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, | |
1643 | +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty | |
1644 | +# string, for the replacement values of the other commands the user is referred | |
1645 | +# to HTML_HEADER. | |
1646 | +# This tag requires that the tag GENERATE_LATEX is set to YES. | |
1647 | + | |
1648 | +LATEX_HEADER = | |
1649 | + | |
1650 | +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the | |
1651 | +# generated LaTeX document. The footer should contain everything after the last | |
1652 | +# chapter. If it is left blank doxygen will generate a standard footer. See | |
1653 | +# LATEX_HEADER for more information on how to generate a default footer and what | |
1654 | +# special commands can be used inside the footer. | |
1655 | +# | |
1656 | +# Note: Only use a user-defined footer if you know what you are doing! | |
1657 | +# This tag requires that the tag GENERATE_LATEX is set to YES. | |
1658 | + | |
1659 | +LATEX_FOOTER = | |
1660 | + | |
1661 | +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined | |
1662 | +# LaTeX style sheets that are included after the standard style sheets created | |
1663 | +# by doxygen. Using this option one can overrule certain style aspects. Doxygen | |
1664 | +# will copy the style sheet files to the output directory. | |
1665 | +# Note: The order of the extra style sheet files is of importance (e.g. the last | |
1666 | +# style sheet in the list overrules the setting of the previous ones in the | |
1667 | +# list). | |
1668 | +# This tag requires that the tag GENERATE_LATEX is set to YES. | |
1669 | + | |
1670 | +LATEX_EXTRA_STYLESHEET = | |
1671 | + | |
1672 | +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or | |
1673 | +# other source files which should be copied to the LATEX_OUTPUT output | |
1674 | +# directory. Note that the files will be copied as-is; there are no commands or | |
1675 | +# markers available. | |
1676 | +# This tag requires that the tag GENERATE_LATEX is set to YES. | |
1677 | + | |
1678 | +LATEX_EXTRA_FILES = | |
1679 | + | |
1680 | +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is | |
1681 | +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will | |
1682 | +# contain links (just like the HTML output) instead of page references. This | |
1683 | +# makes the output suitable for online browsing using a PDF viewer. | |
1684 | +# The default value is: YES. | |
1685 | +# This tag requires that the tag GENERATE_LATEX is set to YES. | |
1686 | + | |
1687 | +PDF_HYPERLINKS = YES | |
1688 | + | |
1689 | +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate | |
1690 | +# the PDF file directly from the LaTeX files. Set this option to YES, to get a | |
1691 | +# higher quality PDF documentation. | |
1692 | +# The default value is: YES. | |
1693 | +# This tag requires that the tag GENERATE_LATEX is set to YES. | |
1694 | + | |
1695 | +USE_PDFLATEX = YES | |
1696 | + | |
1697 | +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode | |
1698 | +# command to the generated LaTeX files. This will instruct LaTeX to keep running | |
1699 | +# if errors occur, instead of asking the user for help. This option is also used | |
1700 | +# when generating formulas in HTML. | |
1701 | +# The default value is: NO. | |
1702 | +# This tag requires that the tag GENERATE_LATEX is set to YES. | |
1703 | + | |
1704 | +LATEX_BATCHMODE = NO | |
1705 | + | |
1706 | +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the | |
1707 | +# index chapters (such as File Index, Compound Index, etc.) in the output. | |
1708 | +# The default value is: NO. | |
1709 | +# This tag requires that the tag GENERATE_LATEX is set to YES. | |
1710 | + | |
1711 | +LATEX_HIDE_INDICES = NO | |
1712 | + | |
1713 | +# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source | |
1714 | +# code with syntax highlighting in the LaTeX output. | |
1715 | +# | |
1716 | +# Note that which sources are shown also depends on other settings such as | |
1717 | +# SOURCE_BROWSER. | |
1718 | +# The default value is: NO. | |
1719 | +# This tag requires that the tag GENERATE_LATEX is set to YES. | |
1720 | + | |
1721 | +LATEX_SOURCE_CODE = NO | |
1722 | + | |
1723 | +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the | |
1724 | +# bibliography, e.g. plainnat, or ieeetr. See | |
1725 | +# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. | |
1726 | +# The default value is: plain. | |
1727 | +# This tag requires that the tag GENERATE_LATEX is set to YES. | |
1728 | + | |
1729 | +LATEX_BIB_STYLE = plain | |
1730 | + | |
1731 | +#--------------------------------------------------------------------------- | |
1732 | +# Configuration options related to the RTF output | |
1733 | +#--------------------------------------------------------------------------- | |
1734 | + | |
1735 | +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The | |
1736 | +# RTF output is optimized for Word 97 and may not look too pretty with other RTF | |
1737 | +# readers/editors. | |
1738 | +# The default value is: NO. | |
1739 | + | |
1740 | +GENERATE_RTF = NO | |
1741 | + | |
1742 | +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a | |
1743 | +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of | |
1744 | +# it. | |
1745 | +# The default directory is: rtf. | |
1746 | +# This tag requires that the tag GENERATE_RTF is set to YES. | |
1747 | + | |
1748 | +RTF_OUTPUT = rtf | |
1749 | + | |
1750 | +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF | |
1751 | +# documents. This may be useful for small projects and may help to save some | |
1752 | +# trees in general. | |
1753 | +# The default value is: NO. | |
1754 | +# This tag requires that the tag GENERATE_RTF is set to YES. | |
1755 | + | |
1756 | +COMPACT_RTF = NO | |
1757 | + | |
1758 | +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will | |
1759 | +# contain hyperlink fields. The RTF file will contain links (just like the HTML | |
1760 | +# output) instead of page references. This makes the output suitable for online | |
1761 | +# browsing using Word or some other Word compatible readers that support those | |
1762 | +# fields. | |
1763 | +# | |
1764 | +# Note: WordPad (write) and others do not support links. | |
1765 | +# The default value is: NO. | |
1766 | +# This tag requires that the tag GENERATE_RTF is set to YES. | |
1767 | + | |
1768 | +RTF_HYPERLINKS = NO | |
1769 | + | |
1770 | +# Load stylesheet definitions from file. Syntax is similar to doxygen's config | |
1771 | +# file, i.e. a series of assignments. You only have to provide replacements, | |
1772 | +# missing definitions are set to their default value. | |
1773 | +# | |
1774 | +# See also section "Doxygen usage" for information on how to generate the | |
1775 | +# default style sheet that doxygen normally uses. | |
1776 | +# This tag requires that the tag GENERATE_RTF is set to YES. | |
1777 | + | |
1778 | +RTF_STYLESHEET_FILE = | |
1779 | + | |
1780 | +# Set optional variables used in the generation of an RTF document. Syntax is | |
1781 | +# similar to doxygen's config file. A template extensions file can be generated | |
1782 | +# using doxygen -e rtf extensionFile. | |
1783 | +# This tag requires that the tag GENERATE_RTF is set to YES. | |
1784 | + | |
1785 | +RTF_EXTENSIONS_FILE = | |
1786 | + | |
1787 | +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code | |
1788 | +# with syntax highlighting in the RTF output. | |
1789 | +# | |
1790 | +# Note that which sources are shown also depends on other settings such as | |
1791 | +# SOURCE_BROWSER. | |
1792 | +# The default value is: NO. | |
1793 | +# This tag requires that the tag GENERATE_RTF is set to YES. | |
1794 | + | |
1795 | +RTF_SOURCE_CODE = NO | |
1796 | + | |
1797 | +#--------------------------------------------------------------------------- | |
1798 | +# Configuration options related to the man page output | |
1799 | +#--------------------------------------------------------------------------- | |
1800 | + | |
1801 | +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for | |
1802 | +# classes and files. | |
1803 | +# The default value is: NO. | |
1804 | + | |
1805 | +GENERATE_MAN = NO | |
1806 | + | |
1807 | +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a | |
1808 | +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of | |
1809 | +# it. A directory man3 will be created inside the directory specified by | |
1810 | +# MAN_OUTPUT. | |
1811 | +# The default directory is: man. | |
1812 | +# This tag requires that the tag GENERATE_MAN is set to YES. | |
1813 | + | |
1814 | +MAN_OUTPUT = man | |
1815 | + | |
1816 | +# The MAN_EXTENSION tag determines the extension that is added to the generated | |
1817 | +# man pages. In case the manual section does not start with a number, the number | |
1818 | +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is | |
1819 | +# optional. | |
1820 | +# The default value is: .3. | |
1821 | +# This tag requires that the tag GENERATE_MAN is set to YES. | |
1822 | + | |
1823 | +MAN_EXTENSION = .3 | |
1824 | + | |
1825 | +# The MAN_SUBDIR tag determines the name of the directory created within | |
1826 | +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by | |
1827 | +# MAN_EXTENSION with the initial . removed. | |
1828 | +# This tag requires that the tag GENERATE_MAN is set to YES. | |
1829 | + | |
1830 | +MAN_SUBDIR = | |
1831 | + | |
1832 | +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it | |
1833 | +# will generate one additional man file for each entity documented in the real | |
1834 | +# man page(s). These additional files only source the real man page, but without | |
1835 | +# them the man command would be unable to find the correct page. | |
1836 | +# The default value is: NO. | |
1837 | +# This tag requires that the tag GENERATE_MAN is set to YES. | |
1838 | + | |
1839 | +MAN_LINKS = NO | |
1840 | + | |
1841 | +#--------------------------------------------------------------------------- | |
1842 | +# Configuration options related to the XML output | |
1843 | +#--------------------------------------------------------------------------- | |
1844 | + | |
1845 | +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that | |
1846 | +# captures the structure of the code including all documentation. | |
1847 | +# The default value is: NO. | |
1848 | + | |
1849 | +GENERATE_XML = NO | |
1850 | + | |
1851 | +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a | |
1852 | +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of | |
1853 | +# it. | |
1854 | +# The default directory is: xml. | |
1855 | +# This tag requires that the tag GENERATE_XML is set to YES. | |
1856 | + | |
1857 | +XML_OUTPUT = xml | |
1858 | + | |
1859 | +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program | |
1860 | +# listings (including syntax highlighting and cross-referencing information) to | |
1861 | +# the XML output. Note that enabling this will significantly increase the size | |
1862 | +# of the XML output. | |
1863 | +# The default value is: YES. | |
1864 | +# This tag requires that the tag GENERATE_XML is set to YES. | |
1865 | + | |
1866 | +XML_PROGRAMLISTING = YES | |
1867 | + | |
1868 | +#--------------------------------------------------------------------------- | |
1869 | +# Configuration options related to the DOCBOOK output | |
1870 | +#--------------------------------------------------------------------------- | |
1871 | + | |
1872 | +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files | |
1873 | +# that can be used to generate PDF. | |
1874 | +# The default value is: NO. | |
1875 | + | |
1876 | +GENERATE_DOCBOOK = NO | |
1877 | + | |
1878 | +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. | |
1879 | +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in | |
1880 | +# front of it. | |
1881 | +# The default directory is: docbook. | |
1882 | +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. | |
1883 | + | |
1884 | +DOCBOOK_OUTPUT = docbook | |
1885 | + | |
1886 | +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the | |
1887 | +# program listings (including syntax highlighting and cross-referencing | |
1888 | +# information) to the DOCBOOK output. Note that enabling this will significantly | |
1889 | +# increase the size of the DOCBOOK output. | |
1890 | +# The default value is: NO. | |
1891 | +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. | |
1892 | + | |
1893 | +DOCBOOK_PROGRAMLISTING = NO | |
1894 | + | |
1895 | +#--------------------------------------------------------------------------- | |
1896 | +# Configuration options for the AutoGen Definitions output | |
1897 | +#--------------------------------------------------------------------------- | |
1898 | + | |
1899 | +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an | |
1900 | +# AutoGen Definitions (see http://autogen.sf.net) file that captures the | |
1901 | +# structure of the code including all documentation. Note that this feature is | |
1902 | +# still experimental and incomplete at the moment. | |
1903 | +# The default value is: NO. | |
1904 | + | |
1905 | +GENERATE_AUTOGEN_DEF = NO | |
1906 | + | |
1907 | +#--------------------------------------------------------------------------- | |
1908 | +# Configuration options related to the Perl module output | |
1909 | +#--------------------------------------------------------------------------- | |
1910 | + | |
1911 | +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module | |
1912 | +# file that captures the structure of the code including all documentation. | |
1913 | +# | |
1914 | +# Note that this feature is still experimental and incomplete at the moment. | |
1915 | +# The default value is: NO. | |
1916 | + | |
1917 | +GENERATE_PERLMOD = NO | |
1918 | + | |
1919 | +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary | |
1920 | +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI | |
1921 | +# output from the Perl module output. | |
1922 | +# The default value is: NO. | |
1923 | +# This tag requires that the tag GENERATE_PERLMOD is set to YES. | |
1924 | + | |
1925 | +PERLMOD_LATEX = NO | |
1926 | + | |
1927 | +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely | |
1928 | +# formatted so it can be parsed by a human reader. This is useful if you want to | |
1929 | +# understand what is going on. On the other hand, if this tag is set to NO, the | |
1930 | +# size of the Perl module output will be much smaller and Perl will parse it | |
1931 | +# just the same. | |
1932 | +# The default value is: YES. | |
1933 | +# This tag requires that the tag GENERATE_PERLMOD is set to YES. | |
1934 | + | |
1935 | +PERLMOD_PRETTY = YES | |
1936 | + | |
1937 | +# The names of the make variables in the generated doxyrules.make file are | |
1938 | +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful | |
1939 | +# so different doxyrules.make files included by the same Makefile don't | |
1940 | +# overwrite each other's variables. | |
1941 | +# This tag requires that the tag GENERATE_PERLMOD is set to YES. | |
1942 | + | |
1943 | +PERLMOD_MAKEVAR_PREFIX = | |
1944 | + | |
1945 | +#--------------------------------------------------------------------------- | |
1946 | +# Configuration options related to the preprocessor | |
1947 | +#--------------------------------------------------------------------------- | |
1948 | + | |
1949 | +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all | |
1950 | +# C-preprocessor directives found in the sources and include files. | |
1951 | +# The default value is: YES. | |
1952 | + | |
1953 | +ENABLE_PREPROCESSING = YES | |
1954 | + | |
1955 | +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names | |
1956 | +# in the source code. If set to NO, only conditional compilation will be | |
1957 | +# performed. Macro expansion can be done in a controlled way by setting | |
1958 | +# EXPAND_ONLY_PREDEF to YES. | |
1959 | +# The default value is: NO. | |
1960 | +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. | |
1961 | + | |
1962 | +MACRO_EXPANSION = NO | |
1963 | + | |
1964 | +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then | |
1965 | +# the macro expansion is limited to the macros specified with the PREDEFINED and | |
1966 | +# EXPAND_AS_DEFINED tags. | |
1967 | +# The default value is: NO. | |
1968 | +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. | |
1969 | + | |
1970 | +EXPAND_ONLY_PREDEF = NO | |
1971 | + | |
1972 | +# If the SEARCH_INCLUDES tag is set to YES, the include files in the | |
1973 | +# INCLUDE_PATH will be searched if a #include is found. | |
1974 | +# The default value is: YES. | |
1975 | +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. | |
1976 | + | |
1977 | +SEARCH_INCLUDES = YES | |
1978 | + | |
1979 | +# The INCLUDE_PATH tag can be used to specify one or more directories that | |
1980 | +# contain include files that are not input files but should be processed by the | |
1981 | +# preprocessor. | |
1982 | +# This tag requires that the tag SEARCH_INCLUDES is set to YES. | |
1983 | + | |
1984 | +INCLUDE_PATH = | |
1985 | + | |
1986 | +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard | |
1987 | +# patterns (like *.h and *.hpp) to filter out the header-files in the | |
1988 | +# directories. If left blank, the patterns specified with FILE_PATTERNS will be | |
1989 | +# used. | |
1990 | +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. | |
1991 | + | |
1992 | +INCLUDE_FILE_PATTERNS = | |
1993 | + | |
1994 | +# The PREDEFINED tag can be used to specify one or more macro names that are | |
1995 | +# defined before the preprocessor is started (similar to the -D option of e.g. | |
1996 | +# gcc). The argument of the tag is a list of macros of the form: name or | |
1997 | +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" | |
1998 | +# is assumed. To prevent a macro definition from being undefined via #undef or | |
1999 | +# recursively expanded use the := operator instead of the = operator. | |
2000 | +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. | |
2001 | + | |
2002 | +PREDEFINED = | |
2003 | + | |
2004 | +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this | |
2005 | +# tag can be used to specify a list of macro names that should be expanded. The | |
2006 | +# macro definition that is found in the sources will be used. Use the PREDEFINED | |
2007 | +# tag if you want to use a different macro definition that overrules the | |
2008 | +# definition found in the source code. | |
2009 | +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. | |
2010 | + | |
2011 | +EXPAND_AS_DEFINED = | |
2012 | + | |
2013 | +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will | |
2014 | +# remove all references to function-like macros that are alone on a line, have | |
2015 | +# an all uppercase name, and do not end with a semicolon. Such function macros | |
2016 | +# are typically used for boiler-plate code, and will confuse the parser if not | |
2017 | +# removed. | |
2018 | +# The default value is: YES. | |
2019 | +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. | |
2020 | + | |
2021 | +SKIP_FUNCTION_MACROS = YES | |
2022 | + | |
2023 | +#--------------------------------------------------------------------------- | |
2024 | +# Configuration options related to external references | |
2025 | +#--------------------------------------------------------------------------- | |
2026 | + | |
2027 | +# The TAGFILES tag can be used to specify one or more tag files. For each tag | |
2028 | +# file the location of the external documentation should be added. The format of | |
2029 | +# a tag file without this location is as follows: | |
2030 | +# TAGFILES = file1 file2 ... | |
2031 | +# Adding location for the tag files is done as follows: | |
2032 | +# TAGFILES = file1=loc1 "file2 = loc2" ... | |
2033 | +# where loc1 and loc2 can be relative or absolute paths or URLs. See the | |
2034 | +# section "Linking to external documentation" for more information about the use | |
2035 | +# of tag files. | |
2036 | +# Note: Each tag file must have a unique name (where the name does NOT include | |
2037 | +# the path). If a tag file is not located in the directory in which doxygen is | |
2038 | +# run, you must also specify the path to the tagfile here. | |
2039 | + | |
2040 | +TAGFILES = | |
2041 | + | |
2042 | +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a | |
2043 | +# tag file that is based on the input files it reads. See section "Linking to | |
2044 | +# external documentation" for more information about the usage of tag files. | |
2045 | + | |
2046 | +GENERATE_TAGFILE = | |
2047 | + | |
2048 | +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in | |
2049 | +# the class index. If set to NO, only the inherited external classes will be | |
2050 | +# listed. | |
2051 | +# The default value is: NO. | |
2052 | + | |
2053 | +ALLEXTERNALS = NO | |
2054 | + | |
2055 | +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed | |
2056 | +# in the modules index. If set to NO, only the current project's groups will be | |
2057 | +# listed. | |
2058 | +# The default value is: YES. | |
2059 | + | |
2060 | +EXTERNAL_GROUPS = YES | |
2061 | + | |
2062 | +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in | |
2063 | +# the related pages index. If set to NO, only the current project's pages will | |
2064 | +# be listed. | |
2065 | +# The default value is: YES. | |
2066 | + | |
2067 | +EXTERNAL_PAGES = YES | |
2068 | + | |
2069 | +# The PERL_PATH should be the absolute path and name of the perl script | |
2070 | +# interpreter (i.e. the result of 'which perl'). | |
2071 | +# The default file (with absolute path) is: /usr/bin/perl. | |
2072 | + | |
2073 | +PERL_PATH = /usr/bin/perl | |
2074 | + | |
2075 | +#--------------------------------------------------------------------------- | |
2076 | +# Configuration options related to the dot tool | |
2077 | +#--------------------------------------------------------------------------- | |
2078 | + | |
2079 | +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram | |
2080 | +# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to | |
2081 | +# NO turns the diagrams off. Note that this option also works with HAVE_DOT | |
2082 | +# disabled, but it is recommended to install and use dot, since it yields more | |
2083 | +# powerful graphs. | |
2084 | +# The default value is: YES. | |
2085 | + | |
2086 | +CLASS_DIAGRAMS = YES | |
2087 | + | |
2088 | +# You can define message sequence charts within doxygen comments using the \msc | |
2089 | +# command. Doxygen will then run the mscgen tool (see: | |
2090 | +# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the | |
2091 | +# documentation. The MSCGEN_PATH tag allows you to specify the directory where | |
2092 | +# the mscgen tool resides. If left empty the tool is assumed to be found in the | |
2093 | +# default search path. | |
2094 | + | |
2095 | +MSCGEN_PATH = | |
2096 | + | |
2097 | +# You can include diagrams made with dia in doxygen documentation. Doxygen will | |
2098 | +# then run dia to produce the diagram and insert it in the documentation. The | |
2099 | +# DIA_PATH tag allows you to specify the directory where the dia binary resides. | |
2100 | +# If left empty dia is assumed to be found in the default search path. | |
2101 | + | |
2102 | +DIA_PATH = | |
2103 | + | |
2104 | +# If set to YES the inheritance and collaboration graphs will hide inheritance | |
2105 | +# and usage relations if the target is undocumented or is not a class. | |
2106 | +# The default value is: YES. | |
2107 | + | |
2108 | +HIDE_UNDOC_RELATIONS = YES | |
2109 | + | |
2110 | +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is | |
2111 | +# available from the path. This tool is part of Graphviz (see: | |
2112 | +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent | |
2113 | +# Bell Labs. The other options in this section have no effect if this option is | |
2114 | +# set to NO | |
2115 | +# The default value is: NO. | |
2116 | + | |
2117 | +HAVE_DOT = NO | |
2118 | + | |
2119 | +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed | |
2120 | +# to run in parallel. When set to 0 doxygen will base this on the number of | |
2121 | +# processors available in the system. You can set it explicitly to a value | |
2122 | +# larger than 0 to get control over the balance between CPU load and processing | |
2123 | +# speed. | |
2124 | +# Minimum value: 0, maximum value: 32, default value: 0. | |
2125 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2126 | + | |
2127 | +DOT_NUM_THREADS = 0 | |
2128 | + | |
2129 | +# When you want a differently looking font in the dot files that doxygen | |
2130 | +# generates you can specify the font name using DOT_FONTNAME. You need to make | |
2131 | +# sure dot is able to find the font, which can be done by putting it in a | |
2132 | +# standard location or by setting the DOTFONTPATH environment variable or by | |
2133 | +# setting DOT_FONTPATH to the directory containing the font. | |
2134 | +# The default value is: Helvetica. | |
2135 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2136 | + | |
2137 | +DOT_FONTNAME = Helvetica | |
2138 | + | |
2139 | +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of | |
2140 | +# dot graphs. | |
2141 | +# Minimum value: 4, maximum value: 24, default value: 10. | |
2142 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2143 | + | |
2144 | +DOT_FONTSIZE = 10 | |
2145 | + | |
2146 | +# By default doxygen will tell dot to use the default font as specified with | |
2147 | +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set | |
2148 | +# the path where dot can find it using this tag. | |
2149 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2150 | + | |
2151 | +DOT_FONTPATH = | |
2152 | + | |
2153 | +# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for | |
2154 | +# each documented class showing the direct and indirect inheritance relations. | |
2155 | +# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. | |
2156 | +# The default value is: YES. | |
2157 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2158 | + | |
2159 | +CLASS_GRAPH = YES | |
2160 | + | |
2161 | +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a | |
2162 | +# graph for each documented class showing the direct and indirect implementation | |
2163 | +# dependencies (inheritance, containment, and class references variables) of the | |
2164 | +# class with other documented classes. | |
2165 | +# The default value is: YES. | |
2166 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2167 | + | |
2168 | +COLLABORATION_GRAPH = YES | |
2169 | + | |
2170 | +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for | |
2171 | +# groups, showing the direct groups dependencies. | |
2172 | +# The default value is: YES. | |
2173 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2174 | + | |
2175 | +GROUP_GRAPHS = YES | |
2176 | + | |
2177 | +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and | |
2178 | +# collaboration diagrams in a style similar to the OMG's Unified Modeling | |
2179 | +# Language. | |
2180 | +# The default value is: NO. | |
2181 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2182 | + | |
2183 | +UML_LOOK = NO | |
2184 | + | |
2185 | +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the | |
2186 | +# class node. If there are many fields or methods and many nodes the graph may | |
2187 | +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the | |
2188 | +# number of items for each type to make the size more manageable. Set this to 0 | |
2189 | +# for no limit. Note that the threshold may be exceeded by 50% before the limit | |
2190 | +# is enforced. So when you set the threshold to 10, up to 15 fields may appear, | |
2191 | +# but if the number exceeds 15, the total amount of fields shown is limited to | |
2192 | +# 10. | |
2193 | +# Minimum value: 0, maximum value: 100, default value: 10. | |
2194 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2195 | + | |
2196 | +UML_LIMIT_NUM_FIELDS = 10 | |
2197 | + | |
2198 | +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and | |
2199 | +# collaboration graphs will show the relations between templates and their | |
2200 | +# instances. | |
2201 | +# The default value is: NO. | |
2202 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2203 | + | |
2204 | +TEMPLATE_RELATIONS = NO | |
2205 | + | |
2206 | +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to | |
2207 | +# YES then doxygen will generate a graph for each documented file showing the | |
2208 | +# direct and indirect include dependencies of the file with other documented | |
2209 | +# files. | |
2210 | +# The default value is: YES. | |
2211 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2212 | + | |
2213 | +INCLUDE_GRAPH = YES | |
2214 | + | |
2215 | +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are | |
2216 | +# set to YES then doxygen will generate a graph for each documented file showing | |
2217 | +# the direct and indirect include dependencies of the file with other documented | |
2218 | +# files. | |
2219 | +# The default value is: YES. | |
2220 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2221 | + | |
2222 | +INCLUDED_BY_GRAPH = YES | |
2223 | + | |
2224 | +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call | |
2225 | +# dependency graph for every global function or class method. | |
2226 | +# | |
2227 | +# Note that enabling this option will significantly increase the time of a run. | |
2228 | +# So in most cases it will be better to enable call graphs for selected | |
2229 | +# functions only using the \callgraph command. | |
2230 | +# The default value is: NO. | |
2231 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2232 | + | |
2233 | +CALL_GRAPH = NO | |
2234 | + | |
2235 | +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller | |
2236 | +# dependency graph for every global function or class method. | |
2237 | +# | |
2238 | +# Note that enabling this option will significantly increase the time of a run. | |
2239 | +# So in most cases it will be better to enable caller graphs for selected | |
2240 | +# functions only using the \callergraph command. | |
2241 | +# The default value is: NO. | |
2242 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2243 | + | |
2244 | +CALLER_GRAPH = NO | |
2245 | + | |
2246 | +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical | |
2247 | +# hierarchy of all classes instead of a textual one. | |
2248 | +# The default value is: YES. | |
2249 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2250 | + | |
2251 | +GRAPHICAL_HIERARCHY = YES | |
2252 | + | |
2253 | +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the | |
2254 | +# dependencies a directory has on other directories in a graphical way. The | |
2255 | +# dependency relations are determined by the #include relations between the | |
2256 | +# files in the directories. | |
2257 | +# The default value is: YES. | |
2258 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2259 | + | |
2260 | +DIRECTORY_GRAPH = YES | |
2261 | + | |
2262 | +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images | |
2263 | +# generated by dot. | |
2264 | +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order | |
2265 | +# to make the SVG files visible in IE 9+ (other browsers do not have this | |
2266 | +# requirement). | |
2267 | +# Possible values are: png, jpg, gif and svg. | |
2268 | +# The default value is: png. | |
2269 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2270 | + | |
2271 | +DOT_IMAGE_FORMAT = png | |
2272 | + | |
2273 | +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to | |
2274 | +# enable generation of interactive SVG images that allow zooming and panning. | |
2275 | +# | |
2276 | +# Note that this requires a modern browser other than Internet Explorer. Tested | |
2277 | +# and working are Firefox, Chrome, Safari, and Opera. | |
2278 | +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make | |
2279 | +# the SVG files visible. Older versions of IE do not have SVG support. | |
2280 | +# The default value is: NO. | |
2281 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2282 | + | |
2283 | +INTERACTIVE_SVG = NO | |
2284 | + | |
2285 | +# The DOT_PATH tag can be used to specify the path where the dot tool can be | |
2286 | +# found. If left blank, it is assumed the dot tool can be found in the path. | |
2287 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2288 | + | |
2289 | +DOT_PATH = | |
2290 | + | |
2291 | +# The DOTFILE_DIRS tag can be used to specify one or more directories that | |
2292 | +# contain dot files that are included in the documentation (see the \dotfile | |
2293 | +# command). | |
2294 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2295 | + | |
2296 | +DOTFILE_DIRS = | |
2297 | + | |
2298 | +# The MSCFILE_DIRS tag can be used to specify one or more directories that | |
2299 | +# contain msc files that are included in the documentation (see the \mscfile | |
2300 | +# command). | |
2301 | + | |
2302 | +MSCFILE_DIRS = | |
2303 | + | |
2304 | +# The DIAFILE_DIRS tag can be used to specify one or more directories that | |
2305 | +# contain dia files that are included in the documentation (see the \diafile | |
2306 | +# command). | |
2307 | + | |
2308 | +DIAFILE_DIRS = | |
2309 | + | |
2310 | +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the | |
2311 | +# path where java can find the plantuml.jar file. If left blank, it is assumed | |
2312 | +# PlantUML is not used or called during a preprocessing step. Doxygen will | |
2313 | +# generate a warning when it encounters a \startuml command in this case and | |
2314 | +# will not generate output for the diagram. | |
2315 | + | |
2316 | +PLANTUML_JAR_PATH = | |
2317 | + | |
2318 | +# When using plantuml, the specified paths are searched for files specified by | |
2319 | +# the !include statement in a plantuml block. | |
2320 | + | |
2321 | +PLANTUML_INCLUDE_PATH = | |
2322 | + | |
2323 | +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes | |
2324 | +# that will be shown in the graph. If the number of nodes in a graph becomes | |
2325 | +# larger than this value, doxygen will truncate the graph, which is visualized | |
2326 | +# by representing a node as a red box. Note that doxygen if the number of direct | |
2327 | +# children of the root node in a graph is already larger than | |
2328 | +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that | |
2329 | +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. | |
2330 | +# Minimum value: 0, maximum value: 10000, default value: 50. | |
2331 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2332 | + | |
2333 | +DOT_GRAPH_MAX_NODES = 50 | |
2334 | + | |
2335 | +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs | |
2336 | +# generated by dot. A depth value of 3 means that only nodes reachable from the | |
2337 | +# root by following a path via at most 3 edges will be shown. Nodes that lay | |
2338 | +# further from the root node will be omitted. Note that setting this option to 1 | |
2339 | +# or 2 may greatly reduce the computation time needed for large code bases. Also | |
2340 | +# note that the size of a graph can be further restricted by | |
2341 | +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. | |
2342 | +# Minimum value: 0, maximum value: 1000, default value: 0. | |
2343 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2344 | + | |
2345 | +MAX_DOT_GRAPH_DEPTH = 0 | |
2346 | + | |
2347 | +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent | |
2348 | +# background. This is disabled by default, because dot on Windows does not seem | |
2349 | +# to support this out of the box. | |
2350 | +# | |
2351 | +# Warning: Depending on the platform used, enabling this option may lead to | |
2352 | +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to | |
2353 | +# read). | |
2354 | +# The default value is: NO. | |
2355 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2356 | + | |
2357 | +DOT_TRANSPARENT = NO | |
2358 | + | |
2359 | +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output | |
2360 | +# files in one run (i.e. multiple -o and -T options on the command line). This | |
2361 | +# makes dot run faster, but since only newer versions of dot (>1.8.10) support | |
2362 | +# this, this feature is disabled by default. | |
2363 | +# The default value is: NO. | |
2364 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2365 | + | |
2366 | +DOT_MULTI_TARGETS = NO | |
2367 | + | |
2368 | +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page | |
2369 | +# explaining the meaning of the various boxes and arrows in the dot generated | |
2370 | +# graphs. | |
2371 | +# The default value is: YES. | |
2372 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2373 | + | |
2374 | +GENERATE_LEGEND = YES | |
2375 | + | |
2376 | +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot | |
2377 | +# files that are used to generate the various graphs. | |
2378 | +# The default value is: YES. | |
2379 | +# This tag requires that the tag HAVE_DOT is set to YES. | |
2380 | + | |
2381 | +DOT_CLEANUP = YES | |
2382 | + | ... | ... |
1 | +++ a/FindFANN.cmake | |
1 | +# | |
2 | +# Windows users: define the GLEW_PATH environment variable to point | |
3 | +# to the directory containing: | |
4 | +# include/fann.h | |
5 | +# lib/*fann.lib | |
6 | + | |
7 | + | |
8 | +# FANN_FOUND - system has fann | |
9 | +# FANN_INCLUDE_DIRS - the fann include directory | |
10 | +# FANN_LIBRARIES - Link these to use fann | |
11 | +# FANN_DEFINITIONS - Compiler switches required for using fann | |
12 | +# | |
13 | + | |
14 | +if(FANN_LIBRARIES AND FANN_INCLUDE_DIRS) | |
15 | + set(FANN_FOUND TRUE) | |
16 | +else() | |
17 | + find_path(FANN_INCLUDE_DIR | |
18 | + NAMES | |
19 | + fann.h | |
20 | + PATHS | |
21 | + $ENV{FANN_PATH}/include | |
22 | + ${FANN_DIR}/include | |
23 | + /usr/include | |
24 | + /usr/local/include | |
25 | + /opt/local/include | |
26 | + /sw/include | |
27 | + ) | |
28 | + | |
29 | + set( _libraries doublefann floatfann ) | |
30 | + | |
31 | + foreach( _lib ${_libraries} ) | |
32 | + string( TOUPPER ${_lib} _name ) | |
33 | + | |
34 | + find_library(${_name}_LIBRARY | |
35 | + NAMES | |
36 | + ${_lib} | |
37 | + PATHS | |
38 | + $ENV{FANN_PATH}/lib | |
39 | + ${FANN_DIR}/lib | |
40 | + /usr/lib | |
41 | + /usr/local/lib | |
42 | + /opt/local/lib | |
43 | + /sw/lib | |
44 | + ) | |
45 | + endforeach() | |
46 | + | |
47 | + | |
48 | + set(FANN_INCLUDE_DIRS | |
49 | + ${FANN_INCLUDE_DIR} | |
50 | + ) | |
51 | + | |
52 | + set(FANN_LIBRARIES | |
53 | + ${FANN_LIBRARIES} | |
54 | + ${FANN_LIBRARY} | |
55 | + ${DOUBLEFANN_LIBRARY} | |
56 | + ${FIXEDFANN_LIBRARY} | |
57 | + ${FLOATFANN_LIBRARY} | |
58 | + ) | |
59 | + | |
60 | + if( UNIX ) | |
61 | + set( FANN_LIBRARIES ${FANN_LIBRARIES} m ) | |
62 | + endif() | |
63 | + | |
64 | + if(FANN_INCLUDE_DIRS AND FANN_LIBRARIES) | |
65 | + set(FANN_FOUND TRUE) | |
66 | + endif() | |
67 | + | |
68 | + if(FANN_FOUND) | |
69 | + if(NOT FANN_FIND_QUIETLY) | |
70 | + message(STATUS "Found FANN") | |
71 | + #message(STATUS "FANN_INCLUDE_DIRS: ${FANN_INCLUDE_DIRS}") | |
72 | + #message(STATUS "FANN_LIBRARIES: ${FANN_LIBRARIES}") | |
73 | + endif() | |
74 | + else() | |
75 | + if(FANN_FIND_REQUIRED) | |
76 | + message(FATAL_ERROR "Could not find FANN") | |
77 | + endif() | |
78 | + endif() | |
79 | + | |
80 | + mark_as_advanced(FANN_INCLUDE_DIRS FANN_LIBRARIES) | |
81 | +endif() | ... | ... |
1 | +++ a/FindGLEW.cmake | |
1 | +# Copyright (c) 2012-2016 DreamWorks Animation LLC | |
2 | +# | |
3 | +# All rights reserved. This software is distributed under the | |
4 | +# Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) | |
5 | +# | |
6 | +# Redistributions of source code must retain the above copyright | |
7 | +# and license notice and the following restrictions and disclaimer. | |
8 | +# | |
9 | +# * Neither the name of DreamWorks Animation nor the names of | |
10 | +# its contributors may be used to endorse or promote products derived | |
11 | +# from this software without specific prior written permission. | |
12 | +# | |
13 | +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
14 | +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
15 | +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
16 | +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
17 | +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, | |
18 | +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
19 | +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
20 | +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
21 | +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
22 | +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
23 | +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 | +# IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE | |
25 | +# LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. | |
26 | +# | |
27 | + | |
28 | +#-*-cmake-*- | |
29 | +# - Find GLEW | |
30 | +# | |
31 | +# Author : Nicholas Yue yue.nicholas@gmail.com | |
32 | +# | |
33 | +# This auxiliary CMake file helps in find the GLEW headers and libraries | |
34 | +# | |
35 | +# GLEW_FOUND set if Glew is found. | |
36 | +# GLEW_INCLUDE_DIR GLEW's include directory | |
37 | +# GLEW_GLEW_LIBRARY GLEW libraries | |
38 | +# GLEW_glewmx_LIBRARY GLEWmx libraries (Mulitple Rendering Context) | |
39 | + | |
40 | +FIND_PACKAGE ( PackageHandleStandardArgs ) | |
41 | + | |
42 | +FIND_PATH( GLEW_LOCATION include/GL/glew.h | |
43 | + "$ENV{GLEW_ROOT}" | |
44 | + NO_DEFAULT_PATH | |
45 | + NO_SYSTEM_ENVIRONMENT_PATH | |
46 | + ) | |
47 | + | |
48 | +FIND_PACKAGE_HANDLE_STANDARD_ARGS ( GLEW | |
49 | + REQUIRED_VARS GLEW_LOCATION | |
50 | + ) | |
51 | + | |
52 | +IF ( GLEW_LOCATION ) | |
53 | + | |
54 | + SET( GLEW_INCLUDE_DIR "${GLEW_LOCATION}/include" CACHE STRING "GLEW include path") | |
55 | + | |
56 | + SET ( ORIGINAL_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) | |
57 | + IF (GLEW_USE_STATIC_LIBS) | |
58 | + IF (APPLE) | |
59 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a") | |
60 | + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW PATHS ${GLEW_LOCATION}/lib | |
61 | + NO_DEFAULT_PATH | |
62 | + NO_SYSTEM_ENVIRONMENT_PATH | |
63 | + ) | |
64 | + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEWmx PATHS ${GLEW_LOCATION}/lib | |
65 | + NO_DEFAULT_PATH | |
66 | + NO_SYSTEM_ENVIRONMENT_PATH | |
67 | + ) | |
68 | + # MESSAGE ( "APPLE STATIC" ) | |
69 | + # MESSAGE ( "GLEW_LIBRARY_PATH = " ${GLEW_LIBRARY_PATH} ) | |
70 | + ELSEIF (WIN32) | |
71 | + # Link library | |
72 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".lib") | |
73 | + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW32S PATHS ${GLEW_LOCATION}/lib ) | |
74 | + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEW32MXS PATHS ${GLEW_LOCATION}/lib ) | |
75 | + ELSE (APPLE) | |
76 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a") | |
77 | + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW PATHS ${GLEW_LOCATION}/lib | |
78 | + NO_DEFAULT_PATH | |
79 | + NO_SYSTEM_ENVIRONMENT_PATH | |
80 | + ) | |
81 | + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEWmx PATHS ${GLEW_LOCATION}/lib | |
82 | + NO_DEFAULT_PATH | |
83 | + NO_SYSTEM_ENVIRONMENT_PATH | |
84 | + ) | |
85 | + # MESSAGE ( "LINUX STATIC" ) | |
86 | + # MESSAGE ( "GLEW_LIBRARY_PATH = " ${GLEW_LIBRARY_PATH} ) | |
87 | + ENDIF (APPLE) | |
88 | + ELSE () | |
89 | + IF (APPLE) | |
90 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib") | |
91 | + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW PATHS ${GLEW_LOCATION}/lib ) | |
92 | + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEWmx PATHS ${GLEW_LOCATION}/lib ) | |
93 | + ELSEIF (WIN32) | |
94 | + # Link library | |
95 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".lib") | |
96 | + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW32 PATHS ${GLEW_LOCATION}/lib ) | |
97 | + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEW32mx PATHS ${GLEW_LOCATION}/lib ) | |
98 | + # Load library | |
99 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".dll") | |
100 | + FIND_LIBRARY ( GLEW_DLL_PATH GLEW32 PATHS ${GLEW_LOCATION}/bin | |
101 | + NO_DEFAULT_PATH | |
102 | + NO_SYSTEM_ENVIRONMENT_PATH | |
103 | + ) | |
104 | + FIND_LIBRARY ( GLEWmx_DLL_PATH GLEW32mx PATHS ${GLEW_LOCATION}/bin | |
105 | + NO_DEFAULT_PATH | |
106 | + NO_SYSTEM_ENVIRONMENT_PATH | |
107 | + ) | |
108 | + ELSE (APPLE) | |
109 | + # Unices | |
110 | + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW PATHS ${GLEW_LOCATION}/lib | |
111 | + NO_DEFAULT_PATH | |
112 | + NO_SYSTEM_ENVIRONMENT_PATH | |
113 | + ) | |
114 | + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEWmx PATHS ${GLEW_LOCATION}/lib | |
115 | + NO_DEFAULT_PATH | |
116 | + NO_SYSTEM_ENVIRONMENT_PATH | |
117 | + ) | |
118 | + ENDIF (APPLE) | |
119 | + ENDIF () | |
120 | + # MUST reset | |
121 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ${ORIGINAL_CMAKE_FIND_LIBRARY_SUFFIXES}) | |
122 | + | |
123 | + SET( GLEW_GLEW_LIBRARY ${GLEW_LIBRARY_PATH} CACHE STRING "GLEW library") | |
124 | + SET( GLEW_GLEWmx_LIBRARY ${GLEWmx_LIBRARY_PATH} CACHE STRING "GLEWmx library") | |
125 | + | |
126 | +ENDIF () | ... | ... |
1 | +++ a/FindGLUT.cmake | |
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}/include) | |
50 | + | |
51 | + if( CMAKE_SIZEOF_VOID_P EQUAL 8 ) | |
52 | + find_library( GLUT_glut_LIBRARY NAMES freeglut | |
53 | + PATHS | |
54 | + $ENV{GLUT_ROOT}/lib/x64 | |
55 | + | |
56 | + NO_DEFAULT_PATH | |
57 | + ) | |
58 | + else( CMAKE_SIZEOF_VOID_P EQUAL 8 ) | |
59 | + find_library( GLUT_glut_LIBRARY NAMES glut glut32 freeglut | |
60 | + PATHS | |
61 | + $ENV{GLUT_ROOT}/lib | |
62 | + ) | |
63 | + endif( CMAKE_SIZEOF_VOID_P EQUAL 8 ) | |
64 | + | |
65 | +else () | |
66 | + | |
67 | + if (APPLE) | |
68 | + find_path(GLUT_INCLUDE_DIR glut.h ${OPENGL_LIBRARY_DIR}) | |
69 | + find_library(GLUT_glut_LIBRARY GLUT DOC "GLUT library for OSX") | |
70 | + find_library(GLUT_cocoa_LIBRARY Cocoa DOC "Cocoa framework for OSX") | |
71 | + | |
72 | + if(GLUT_cocoa_LIBRARY AND NOT TARGET GLUT::Cocoa) | |
73 | + add_library(GLUT::Cocoa UNKNOWN IMPORTED) | |
74 | + # Cocoa should always be a Framework, but we check to make sure. | |
75 | + if(GLUT_cocoa_LIBRARY MATCHES "/([^/]+)\\.framework$") | |
76 | + set_target_properties(GLUT::Cocoa PROPERTIES | |
77 | + IMPORTED_LOCATION "${GLUT_cocoa_LIBRARY}/${CMAKE_MATCH_1}") | |
78 | + else() | |
79 | + set_target_properties(GLUT::Cocoa PROPERTIES | |
80 | + IMPORTED_LOCATION "${GLUT_cocoa_LIBRARY}") | |
81 | + endif() | |
82 | + endif() | |
83 | + else () | |
84 | + | |
85 | + if (BEOS) | |
86 | + | |
87 | + set(_GLUT_INC_DIR /boot/develop/headers/os/opengl) | |
88 | + set(_GLUT_glut_LIB_DIR /boot/develop/lib/x86) | |
89 | + | |
90 | + else() | |
91 | + | |
92 | + find_library( GLUT_Xi_LIBRARY Xi | |
93 | + /usr/openwin/lib | |
94 | + ) | |
95 | + | |
96 | + find_library( GLUT_Xmu_LIBRARY Xmu | |
97 | + /usr/openwin/lib | |
98 | + ) | |
99 | + | |
100 | + if(GLUT_Xi_LIBRARY AND NOT TARGET GLUT::Xi) | |
101 | + add_library(GLUT::Xi UNKNOWN IMPORTED) | |
102 | + set_target_properties(GLUT::Xi PROPERTIES | |
103 | + IMPORTED_LOCATION "${GLUT_Xi_LIBRARY}") | |
104 | + endif() | |
105 | + | |
106 | + if(GLUT_Xmu_LIBRARY AND NOT TARGET GLUT::Xmu) | |
107 | + add_library(GLUT::Xmu UNKNOWN IMPORTED) | |
108 | + set_target_properties(GLUT::Xmu PROPERTIES | |
109 | + IMPORTED_LOCATION "${GLUT_Xmu_LIBRARY}") | |
110 | + endif() | |
111 | + | |
112 | + endif () | |
113 | + | |
114 | + find_path( GLUT_INCLUDE_DIR GL/glut.h | |
115 | + /usr/include/GL | |
116 | + /usr/openwin/share/include | |
117 | + /usr/openwin/include | |
118 | + /opt/graphics/OpenGL/include | |
119 | + /opt/graphics/OpenGL/contrib/libglut | |
120 | + ${_GLUT_INC_DIR} | |
121 | + ) | |
122 | + | |
123 | + find_library( GLUT_glut_LIBRARY glut | |
124 | + /usr/openwin/lib | |
125 | + ${_GLUT_glut_LIB_DIR} | |
126 | + ) | |
127 | + | |
128 | + unset(_GLUT_INC_DIR) | |
129 | + unset(_GLUT_glut_LIB_DIR) | |
130 | + | |
131 | + endif () | |
132 | + | |
133 | +endif () | |
134 | + | |
135 | +FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLUT REQUIRED_VARS GLUT_glut_LIBRARY GLUT_INCLUDE_DIR) | |
136 | + | |
137 | +if (GLUT_FOUND) | |
138 | + # Is -lXi and -lXmu required on all platforms that have it? | |
139 | + # If not, we need some way to figure out what platform we are on. | |
140 | + set( GLUT_LIBRARIES | |
141 | + ${GLUT_glut_LIBRARY} | |
142 | + ${GLUT_Xmu_LIBRARY} | |
143 | + ${GLUT_Xi_LIBRARY} | |
144 | + ${GLUT_cocoa_LIBRARY} | |
145 | + ) | |
146 | + | |
147 | + if(NOT TARGET GLUT::GLUT) | |
148 | + add_library(GLUT::GLUT UNKNOWN IMPORTED) | |
149 | + set_target_properties(GLUT::GLUT PROPERTIES | |
150 | + INTERFACE_INCLUDE_DIRECTORIES "${GLUT_INCLUDE_DIR}") | |
151 | + if(GLUT_glut_LIBRARY MATCHES "/([^/]+)\\.framework$") | |
152 | + set_target_properties(GLUT::GLUT PROPERTIES | |
153 | + IMPORTED_LOCATION "${GLUT_glut_LIBRARY}/${CMAKE_MATCH_1}") | |
154 | + else() | |
155 | + set_target_properties(GLUT::GLUT PROPERTIES | |
156 | + IMPORTED_LOCATION "${GLUT_glut_LIBRARY}") | |
157 | + endif() | |
158 | + | |
159 | + if(TARGET GLUT::Xmu) | |
160 | + set_property(TARGET GLUT::GLUT APPEND | |
161 | + PROPERTY INTERFACE_LINK_LIBRARIES GLUT::Xmu) | |
162 | + endif() | |
163 | + | |
164 | + if(TARGET GLUT::Xi) | |
165 | + set_property(TARGET GLUT::GLUT APPEND | |
166 | + PROPERTY INTERFACE_LINK_LIBRARIES GLUT::Xi) | |
167 | + endif() | |
168 | + | |
169 | + if(TARGET GLUT::Cocoa) | |
170 | + set_property(TARGET GLUT::GLUT APPEND | |
171 | + PROPERTY INTERFACE_LINK_LIBRARIES GLUT::Cocoa) | |
172 | + endif() | |
173 | + endif() | |
174 | + | |
175 | + #The following deprecated settings are for backwards compatibility with CMake1.4 | |
176 | + set (GLUT_LIBRARY ${GLUT_LIBRARIES}) | |
177 | + set (GLUT_INCLUDE_PATH ${GLUT_INCLUDE_DIR}) | |
178 | +endif() | |
179 | + | |
180 | +mark_as_advanced( | |
181 | + GLUT_INCLUDE_DIR | |
182 | + GLUT_glut_LIBRARY | |
183 | + GLUT_Xmu_LIBRARY | |
184 | + GLUT_Xi_LIBRARY | |
185 | + ) | ... | ... |
1 | +++ a/FindLAPACKE.cmake | |
1 | +# - Try to find LAPACKE | |
2 | +# | |
3 | +# Once done this will define | |
4 | +# LAPACKE_FOUND - System has LAPACKE | |
5 | +# LAPACKE_INCLUDE_DIRS - The LAPACKE include directories | |
6 | +# LAPACKE_LIBRARIES - The libraries needed to use LAPACKE | |
7 | +# LAPACKE_DEFINITIONS - Compiler switches required for using LAPACKE | |
8 | +# | |
9 | +# Usually, LAPACKE requires LAPACK and the BLAS. This module does | |
10 | +# not enforce anything about that. | |
11 | + | |
12 | +find_path(LAPACKE_INCLUDE_DIR | |
13 | + NAMES lapacke.h | |
14 | + PATHS $ENV{LAPACK_ROOT} $ENV{LAPACK_PATH} ${INCLUDE_INSTALL_DIR} | |
15 | + PATHS ENV INCLUDE) | |
16 | + | |
17 | +find_library(LAPACKE_LIBRARY liblapacke lapacke | |
18 | + PATHS $ENV{LAPACK_ROOT} $ENV{LAPACK_PATH} ${LIB_INSTALL_DIR} | |
19 | + PATHS ENV LIBRARY_PATH | |
20 | + PATHS ENV LD_LIBRARY_PATH) | |
21 | + | |
22 | +if(MSVC) | |
23 | + find_library(LAPACK_LIBRARY liblapack lapack | |
24 | + PATHS $ENV{LAPACK_ROOT} $ENV{LAPACK_PATH} ${LIB_INSTALL_DIR} | |
25 | + PATHS ENV LIBRARY_PATH | |
26 | + PATHS ENV LD_LIBRARY_PATH) | |
27 | + | |
28 | + find_library(BLAS_LIBRARY libblas blas | |
29 | + PATHS $ENV{LAPACK_ROOT} $ENV{LAPACK_PATH} ${LIB_INSTALL_DIR} | |
30 | + PATHS ENV LIBRARY_PATH | |
31 | + PATHS ENV LD_LIBRARY_PATH) | |
32 | + | |
33 | +else() | |
34 | + find_library(LAPACK REQUIRED) | |
35 | + find_library(BLAS REQUIRED) | |
36 | +endif() | |
37 | +set(LAPACKE_LIBRARIES ${LAPACKE_LIBRARY} ${LAPACK_LIBRARY} ${BLAS_LIBRARY}) | |
38 | + | |
39 | +include(FindPackageHandleStandardArgs) | |
40 | +find_package_handle_standard_args(LAPACKE DEFAULT_MSG | |
41 | + LAPACKE_INCLUDE_DIR | |
42 | + LAPACKE_LIBRARIES) | |
43 | +mark_as_advanced(LAPACKE_INCLUDE_DIR LAPACKE_LIBRARIES) | ... | ... |
1 | +++ a/FindSTIM.cmake | |
1 | +# finds the STIM library (downloads it if it isn't present) | |
2 | +# set STIMLIB_PATH to the directory containing the stim subdirectory (the stim repository) | |
3 | + | |
4 | +include(FindPackageHandleStandardArgs) | |
5 | + | |
6 | +set(STIM_ROOT $ENV{STIM_ROOT}) | |
7 | + | |
8 | +IF(NOT STIM_ROOT) | |
9 | + MESSAGE("ERROR: STIM_ROOT environment variable must be set!") | |
10 | +ENDIF(NOT STIM_ROOT) | |
11 | + | |
12 | + FIND_PATH(STIM_INCLUDE_DIRS DOC "Path to STIM include directory." | |
13 | + NAMES stim/image/image.h | |
14 | + PATHS ${STIM_ROOT}) | |
15 | + | |
16 | +find_package_handle_standard_args(STIM DEFAULT_MSG STIM_INCLUDE_DIRS) | ... | ... |
1 | +++ a/LICENSE.txt | |
1 | +<<<<<<< HEAD | |
2 | +Copyright (c) 2014, David Mayerich | |
3 | +======= | |
4 | +Copyright (c) 2009, David Mayerich | |
5 | +>>>>>>> a18fe1629f7950f34c604fa4ef6ae0c882efa3a5 | |
6 | +All rights reserved. | |
7 | + | |
8 | +Redistribution and use in source and binary forms, with or without | |
9 | +modification, are permitted provided that the following conditions are met: | |
10 | + | |
11 | +1. Redistributions of source code must retain the above copyright notice, this | |
12 | + list of conditions and the following disclaimer. | |
13 | +2. Redistributions in binary form must reproduce the above copyright notice, | |
14 | + this list of conditions and the following disclaimer in the documentation | |
15 | + and/or other materials provided with the distribution. | |
16 | + | |
17 | +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
18 | +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
19 | +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
20 | +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | |
21 | +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
22 | +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
23 | +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
24 | +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 | +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
26 | +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | + | |
28 | +The views and conclusions contained in the software and documentation are those | |
29 | +of the authors and should not be interpreted as representing official policies, | |
30 | +either expressed or implied, of the FreeBSD Project. | |
0 | 31 | \ No newline at end of file | ... | ... |
1 | +++ a/README.md | |
1 | +HSIproc can be built using CMake (https://cmake.org/) and a C/C++ compiler. | |
2 | + | |
3 | +The STIM codebase is required, but will be cloned automatically if Git (https://git-scm.com/) is installed. The codebase can be downloaded manually here: | |
4 | +https://git.stim.ee.uh.edu/codebase/stimlib | |
5 | + | |
6 | +Required libraries: | |
7 | +OpenCV: http://opencv.org/ | |
8 | + | |
9 | + | |
10 | + | |
11 | +----------------------------------------------------------------------- | |
12 | +Step-by-step instructions: | |
13 | + | |
14 | +1) Download and install CMake | |
15 | + | |
16 | +2) Download and install OpenCV | |
17 | + | |
18 | +3) Download and install Git | |
19 | + | |
20 | +4) Set the CMake source directory to the directory containing this file | |
21 | + | |
22 | +5) Specify the CMake build directory where you want the executable built | |
23 | + | |
24 | +6) Use CMake to Configure and Generate the build environment | |
25 | + | |
26 | +7) Build the software (ex. in Visual Studio you will open the generated solution and compile) | ... | ... |
1 | +++ a/matlab/LoadAgilent.m | |
1 | +%Loads a standard Agilent ResPro binary file (DMD, DRD, SEQ, etc) | |
2 | +% Scalable Tissue Imaging and Modeling Laboratory | |
3 | +% University of Houston | |
4 | +% developer: David Mayerich (mayerich@uh.edu) | |
5 | + | |
6 | +function S = stimLoadAgilent(filename) | |
7 | + | |
8 | + fid = fopen(filename); | |
9 | + fseek(fid, 9, 'bof'); | |
10 | + Z = fread(fid, 1, 'uint16'); | |
11 | + fseek(fid, 13, 'cof'); | |
12 | + X = fread(fid, 1, 'uint16'); | |
13 | + Y = fread(fid, 1, 'uint16'); | |
14 | + | |
15 | + fseek(fid, 1020, 'bof'); | |
16 | + | |
17 | + S = reshape(fread(fid, [X, Y * Z], 'float32'), [X, Y, Z]); | |
18 | + | |
19 | + | |
0 | 20 | \ No newline at end of file | ... | ... |
1 | +++ a/matlab/LoadENVI.m | |
1 | +%loads an ENVI file without any manipulation (changing orientation) | |
2 | +% Scalable Tissue Imaging and Modeling Laboratory | |
3 | +% University of Houston | |
4 | +% developer: David Mayerich (mayerich@uh.edu) | |
5 | + | |
6 | +function M = enviLoadRaw(filename, headername) | |
7 | + | |
8 | + if nargin == 1 | |
9 | + headername = [filename '.hdr']; | |
10 | + end | |
11 | + | |
12 | + h = enviLoadHeader(headername); | |
13 | + | |
14 | + if strcmp(h.interleave, 'bsq') | |
15 | + X = h.samples; | |
16 | + Y = h.lines; | |
17 | + Z = h.bands; | |
18 | + elseif strcmp(h.interleave, 'bil') | |
19 | + X = h.samples; | |
20 | + Y = h.bands; | |
21 | + Z = h.lines; | |
22 | + else | |
23 | + X = h.bands; | |
24 | + Y = h.samples; | |
25 | + Z = h.lines; | |
26 | + end | |
27 | + | |
28 | + fid = fopen(filename); | |
29 | + M = fread(fid, [X, Y*Z], '*float32'); | |
30 | + M = reshape(M, [X, Y, Z]); | |
31 | + | |
32 | + fclose(fid); | |
0 | 33 | \ No newline at end of file | ... | ... |
1 | +++ a/python/train-metrics.py | |
1 | +import sys, string, os, subprocess | |
2 | + | |
3 | +os.system("cls") | |
4 | + | |
5 | +infile = sys.argv[1] | |
6 | + | |
7 | +A = "supervised-class/class_coll.png " | |
8 | +B = "supervised-class/class_epith.png " | |
9 | +C = "supervised-class/class_fibro.png " | |
10 | +D = "supervised-class/class_lymph.png " | |
11 | +E = "supervised-class/class_myo.png " | |
12 | +F = "supervised-class/class_necrosis.png " | |
13 | +G = "supervised-class/class_blood.png " | |
14 | + | |
15 | +Ca = "magenta " | |
16 | +Cb = "lime " | |
17 | +Cc = "pink " | |
18 | +Cd = "purple " | |
19 | +Ce = "yellow " | |
20 | +Cf = "orange " | |
21 | +Cg = "maroon " | |
22 | + | |
23 | +#project to metrics | |
24 | +subprocess.call("hsiproc " + infile + " " + infile + "-met --metrics metrics.txt") | |
25 | + | |
26 | +#create a mask to remove bad pixels | |
27 | +subprocess.call("hsiproc " + infile + "-met " + "finite.bmp --mask-finite") | |
28 | +subprocess.call("hsiproc " + infile + "-met " + infile + "-mask --apply-mask finite.bmp") | |
29 | + | |
30 | +#Baseline correction using a set of wavenumber points specified in baseline.txt | |
31 | +subprocess.call("hsiclass " + infile + "-mask classifier.rf --train " + A + B + C + D + E + F + G + "--verbose") | |
32 | + | |
33 | +#convert to BIP for speed | |
34 | +subprocess.call("hsiproc " + infile + "-mask " + infile + "-bip --convert bip") | |
35 | + | |
36 | +#classify the entire image | |
37 | +subprocess.call("hsiclass " + infile + "-bip " + infile + "-class.bmp " + "--classify classifier.rf --colors " + Ca + Cb + Cc + Cd + Ce + Cf + Cg + "--mask mask.bmp --verbose") | |
0 | 38 | \ No newline at end of file | ... | ... |
1 | +++ a/python/train-pca.py | |
1 | +import sys, string, os, subprocess | |
2 | + | |
3 | +os.system("cls") | |
4 | + | |
5 | +infile = sys.argv[1] | |
6 | + | |
7 | +A = "class/coll.bmp " | |
8 | +B = "class/epith.bmp " | |
9 | +C = "class/fibro.bmp " | |
10 | +D = "class/lymph.bmp " | |
11 | +E = "class/myo.bmp " | |
12 | +F = "class/necrosis.bmp " | |
13 | +G = "class/blood.bmp " | |
14 | + | |
15 | +Ca = "magenta " | |
16 | +Cb = "lime " | |
17 | +Cc = "pink " | |
18 | +Cd = "purple " | |
19 | +Ce = "yellow " | |
20 | +Cf = "orange " | |
21 | +Cg = "maroon " | |
22 | + | |
23 | +#Baseline correction using a set of wavenumber points specified in baseline.txt | |
24 | +subprocess.call("hsiproc " + infile + " " + infile + "-base --baseline baseline.txt") | |
25 | + | |
26 | +#Create a mask to be used later for PCA | |
27 | +subprocess.call("hsiproc " + infile + "-base mask.bmp --build-mask 1650 0.1") | |
28 | + | |
29 | +#Convert to a BIP file. This is generally the fastest file to use, algorithmically. | |
30 | +subprocess.call("hsiproc " + infile + "-base " + infile + "-bip --convert bip") | |
31 | + | |
32 | +#sift | |
33 | +subprocess.call("hsiproc " + infile + "-bip " + infile + "-sift --sift mask.bmp") | |
34 | + | |
35 | +#Normalize to Amide I | |
36 | +subprocess.call("hsiproc " + infile + "-sift " + infile + "-norm --normalize 1650") | |
37 | + | |
38 | +#Calculate the principle components | |
39 | +subprocess.call("hsiproc " + infile + "-norm " + infile + ".sta --pca") | |
40 | + | |
41 | +#project onto the PCs | |
42 | +subprocess.call("hsiproc " + infile + "-norm " + infile + "-pca --project pca.sta 30") | |
43 | + | |
44 | +#unsift | |
45 | +subprocess.call("hsiproc " + infile + "-pca " + infile + "-unsift --unsift mask.bmp") | |
46 | + | |
47 | +#convert back to BSQ | |
48 | +subprocess.call("hsiproc " + infile + "-unsift " + infile + "-final --convert bsq") | |
49 | + | |
50 | +#Baseline correction using a set of wavenumber points specified in baseline.txt | |
51 | +subprocess.call("hsiclass " + infile + "-final " + infile + ".rf --train " + A + B + C + D + E + F + G) | |
52 | + | |
53 | +#classify the entire image | |
54 | +subprocess.call("hsiclass " + infile + "-final " + infile + "-class.bmp " + "--classify classifier.rf --colors " + Ca + Cb + Cc + Cd + Ce + Cf + Cg + "--mask mask.bmp --verbose") | |
0 | 55 | \ No newline at end of file | ... | ... |
1 | +++ a/python/validate.py | |
1 | +import sys, string, os, subprocess | |
2 | + | |
3 | +os.system("cls") | |
4 | + | |
5 | +infile = sys.argv[1] | |
6 | + | |
7 | +Ca = "magenta " | |
8 | +Cb = "lime " | |
9 | +Cc = "pink " | |
10 | +Cd = "purple " | |
11 | +Ce = "yellow " | |
12 | +Cf = "orange " | |
13 | +Cg = "maroon " | |
14 | + | |
15 | +#Baseline correction using a set of wavenumber points specified in baseline.txt | |
16 | +subprocess.call("hsiproc " + infile + " " + infile + "-base --baseline baseline.txt") | |
17 | + | |
18 | +#Create a mask to be used later for PCA | |
19 | +subprocess.call("hsiproc " + infile + "-base mask.bmp --build-mask 1650 0.1") | |
20 | + | |
21 | +#Convert to a BIP file. This is generally the fastest file to use, algorithmically. | |
22 | +subprocess.call("hsiproc " + infile + "-base " + infile + "-bip --convert bip") | |
23 | + | |
24 | +#sift | |
25 | +subprocess.call("hsiproc " + infile + "-bip " + infile + "-sift --sift mask.bmp") | |
26 | + | |
27 | +#Normalize to Amide I | |
28 | +subprocess.call("hsiproc " + infile + "-sift " + infile + "-norm --normalize 1650") | |
29 | + | |
30 | +#project onto pre-computed PCs | |
31 | +subprocess.call("hsiproc " + infile + "-norm " + infile + "-pca --project pca.sta 30") | |
32 | + | |
33 | +#unsift | |
34 | +subprocess.call("hsiproc " + infile + "-pca " + infile + "-final --unsift mask.bmp") | |
35 | + | |
36 | +#classify the entire image | |
37 | +subprocess.call("hsiclass " + infile + "-final " + infile + "-class.bmp " + "--classify classifier.rf --colors " + Ca + Cb + Cc + Cd + Ce + Cf + Cg + "--mask mask.bmp --verbose") | |
0 | 38 | \ No newline at end of file | ... | ... |
1 | +++ a/src/cary-ftir/cary-ftir.cpp | |
1 | +//#define _CRTDBG_MAP_ALLOC | |
2 | +//#include <stdlib.h> | |
3 | +//#include <crtdbg.h> | |
4 | + | |
5 | +#include <iostream> | |
6 | + | |
7 | +#include <stim/parser/arguments.h> | |
8 | +#include <stim/envi/agilent_binary.h> | |
9 | +#include <stim/parser/filename.h> | |
10 | + | |
11 | +stim::arglist args; //generate a list of accepted arguments | |
12 | + | |
13 | +#include <thread> | |
14 | +void progress_thread_double(double* e); //progress bar threaded function | |
15 | + | |
16 | +bool fft = false; //perform an FFT before storing | |
17 | +double wn_low, wn_high; | |
18 | +float elwn; | |
19 | +int udr; | |
20 | + | |
21 | +bool absorbance = false; | |
22 | +stim::agilent_binary<float> background; //store the background data | |
23 | + | |
24 | +bool crop_samples = false; | |
25 | +size_t n_samples; | |
26 | + | |
27 | + | |
28 | +void mosaic_coord(unsigned int &x, unsigned int &y, stim::filename dmd_filename) { | |
29 | + | |
30 | + //get the file prefix | |
31 | + std::string prefix = dmd_filename.get_prefix(); | |
32 | + | |
33 | + //these files are in the format: | |
34 | + // ???????????_xxxxx_yyyyy.dmd | |
35 | + | |
36 | + //find the position of the last underscore | |
37 | + size_t y_start = prefix.find_last_of("_"); | |
38 | + //remove all values between x_start and the end of the string | |
39 | + std::string y_string = prefix.substr(y_start + 1); | |
40 | + | |
41 | + y = atoi(y_string.c_str()); | |
42 | + | |
43 | + //crop out the x coordinate and the last underscore | |
44 | + prefix = prefix.substr(0, y_start); | |
45 | + | |
46 | + //find the y coordinate using the same method as above | |
47 | + size_t x_start = prefix.find_last_of("_"); | |
48 | + std::string x_string = prefix.substr(x_start + 1); | |
49 | + x = atoi(x_string.c_str()); | |
50 | +} | |
51 | + //Use the file list to find the number of tiles along each dimension of the mosaic | |
52 | +void mosaic_size(unsigned int &sx, unsigned int &sy, std::vector<stim::filename> dmd_list) { | |
53 | + sx = sy = 0; | |
54 | + | |
55 | + unsigned int xi, yi; | |
56 | + | |
57 | + //for each dmd file | |
58 | + for (unsigned int i = 0; i < dmd_list.size(); i++) { | |
59 | + | |
60 | + //find the coordinate of the tile represented by this file | |
61 | + mosaic_coord(xi, yi, dmd_list[i]); | |
62 | + | |
63 | + //if the coordinate is larger than the current max, store it as the current max | |
64 | + if (xi > sx) sx = xi; | |
65 | + if (yi > sy) sy = yi; | |
66 | + } | |
67 | + | |
68 | + //add 1 to reflect that the indexing starts at 0 | |
69 | + sx++; sy++; | |
70 | +} | |
71 | + | |
72 | +void save_mosaic(std::vector<stim::filename> tile_list, std::string outfile, stim::agilent_binary<float>* background = NULL) { | |
73 | + | |
74 | + stim::agilent_binary<float> binfile(tile_list[0]); //load the first agilent binary file | |
75 | + size_t ds = binfile.dim(0); //get the detector size | |
76 | + | |
77 | + unsigned int mx, my; | |
78 | + mosaic_size(mx, my, tile_list); //calculate the mosaic size | |
79 | + std::cout << "Building a ["<<mx<<" x "<<my<<"] mosaic with a detector size of (" << ds << " x " << ds <<") pixels"<< std::endl; | |
80 | + std::cout << "Mosaic size: " << mx << " " << my << std::endl; //output the mosaic size | |
81 | + | |
82 | + std::ofstream out(outfile, std::ios::binary); //open a binary file for writing | |
83 | + | |
84 | + size_t nxo = mx * ds; //number of output pixels along x | |
85 | + size_t nyo = my * ds; //number of output pixels along y | |
86 | + size_t nbo; | |
87 | + | |
88 | + size_t bytes_tile_band = ds * ds * sizeof(float); //number of bytes in a tile band | |
89 | + size_t bytes_out_band = bytes_tile_band * mx * my; //number of bytes in an output image band | |
90 | + | |
91 | + double progress = 0.0; | |
92 | + std::thread t1(progress_thread_double, &progress); //start the progress bar thread | |
93 | + size_t xo, yo, io; | |
94 | + size_t ii; | |
95 | + stim::envi_header header; | |
96 | + bool header_flag = true; | |
97 | + for (size_t ty = 0; ty < my; ty++) { | |
98 | + for (size_t tx = 0; tx < mx; tx++) { | |
99 | + xo = tx * ds; //calculate the x output position for the current tile | |
100 | + stim::agilent_binary<float> I(tile_list[tx * my + ty].str()); | |
101 | + if (crop_samples) I.crop(n_samples); //crop samples if necessary to reduce spectral resolution | |
102 | + if (fft) I = I.fft(wn_low, wn_high, elwn, udr); //if an FFT is requested, perform it | |
103 | + if (background) I.absorbance(background); //if the user provides a background file | |
104 | + if (header_flag) { | |
105 | + header = I.create_header(); | |
106 | + header_flag = false; | |
107 | + } | |
108 | + nbo = I.dim(2); //get the number of bands in the output image | |
109 | + for (size_t b = 0; b < nbo; b++) { //for each band in the input | |
110 | + for (size_t yi = 0; yi < ds; yi++) { //for each line in the input image | |
111 | + yo = ty * ds + ds - yi - 1; //calculate the y output position | |
112 | + io = (b * nxo * nyo + yo * nxo + xo); //calculate the output position as a 1d index | |
113 | + ii = (b * ds * ds + yi * ds); //calculate the input position as a 1d index | |
114 | + out.seekp(io * sizeof(float)); //seek to the correct output location | |
115 | + out.write(I.data() + ii * sizeof(float), ds * sizeof(float)); //copy the line from input to output | |
116 | + } | |
117 | + } | |
118 | + progress = (double)(ty * mx + tx + 1) / (double)(mx * my) * 100; | |
119 | + } | |
120 | + } | |
121 | + out.close(); | |
122 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
123 | + | |
124 | + header.samples = mx * ds; | |
125 | + header.lines = my * ds; | |
126 | + header.save(outfile + ".hdr"); | |
127 | +} | |
128 | + | |
129 | +void output_files(std::vector<stim::filename> infiles, std::string outfile) { | |
130 | + if (infiles.size() == 1) { | |
131 | + std::cout << "source file: " << infiles[0].str() << std::endl; | |
132 | + } | |
133 | + else { | |
134 | + std::cout << "number of input files: " << infiles.size() << std::endl; | |
135 | + } | |
136 | + std::cout << "destination file: " << outfile << std::endl; | |
137 | +} | |
138 | + | |
139 | +int main(int argc, char* argv[]){ | |
140 | + | |
141 | + args.add("help", "print help"); | |
142 | + args.add("spacing", "specify the spectral resolution", "", "positive integer specifying wavenumber spacing"); | |
143 | + args.add("fft", "perform a fourier transform of the data before assembling the mosaic", "", "optional wavenumber range (override UDR), ex: 900 3500"); | |
144 | + args.add("udr", "udr filter used for imaging", "4", "(4 or 8 supported)"); | |
145 | + args.add("elwn", "ELWN tuning number", "15798.0039", "HeNe sampling rate (in cm^(-1))"); | |
146 | + args.add("background", "specify a background file for measuring absorbance", "", "filename.seq"); | |
147 | + args.add("cuda", "specify a CUDA device for the FFT", "0", "index of CUDA device (-1 forces CPU only)"); | |
148 | + args.parse(argc, argv); //parse the argument list | |
149 | + | |
150 | + if (args.nargs() < 2 || args["help"]) { | |
151 | + std::cout << "Usage: " << std::endl<<std::endl; | |
152 | + std::cout << "\tGenerate an ENVI mosaic from a set of tiles produced by a Cary FTIR imaging system:" << std::endl; | |
153 | + std::cout << "\t\t>> cary-ftir input_files/*.dmd output_mosaic" << std::endl << std::endl; | |
154 | + std::cout << args.str() << std::endl; | |
155 | + exit(1); | |
156 | + } | |
157 | + | |
158 | + stim::filename infile(args.arg(0)); | |
159 | + std::vector<stim::filename> in; //create a list of input files | |
160 | + if (args.nargs() == 2) { | |
161 | + if (infile.wildcards()) in = infile.get_list(); //if a wildcard is specified, get the file list | |
162 | + else in.push_back(infile); //if a single file is specified, create a file list of 1 | |
163 | + } | |
164 | + //if the user specifies several files on the command line | |
165 | + else { | |
166 | + for (size_t f = 0; f < args.nargs() - 1; f++) { //for each file specified | |
167 | + in.push_back(args.arg(f)); //add the file to the file list | |
168 | + } | |
169 | + } | |
170 | + | |
171 | + std::string outfilename = args.arg(args.nargs() - 1); //get the output file | |
172 | + | |
173 | + output_files(in, outfilename); | |
174 | + | |
175 | + udr = args["udr"].as_int(); //save the UDR filter type | |
176 | + if (udr == 4) { | |
177 | + wn_low = 900; | |
178 | + wn_high = 3900; | |
179 | + } | |
180 | + else { | |
181 | + wn_low = 800; | |
182 | + wn_high = 1900; | |
183 | + } | |
184 | + | |
185 | + if (args["fft"].is_set()) { | |
186 | + fft = true; //set the fft flag to true | |
187 | + | |
188 | + if (args["fft"].nargs() >= 1) { | |
189 | + if(args["fft"].is_num(0)) | |
190 | + wn_low = args["fft"].as_float(0); | |
191 | + else { | |
192 | + std::cout << "ERROR: FFT output range must be a number: " << args["fft"].as_string(0) << std::endl; | |
193 | + return 1; | |
194 | + } | |
195 | + } | |
196 | + if (args["fft"].nargs() >= 2) { | |
197 | + if (args["fft"].is_num(1)) | |
198 | + wn_high = args["fft"].as_float(1); | |
199 | + else { | |
200 | + std::cout << "ERROR: FFT output range must be a number: " << args["fft"].as_string(1) << std::endl; | |
201 | + return 1; | |
202 | + } | |
203 | + } | |
204 | + | |
205 | + } | |
206 | + | |
207 | + elwn = (float)args["elwn"].as_float(); | |
208 | + | |
209 | + if (args["spacing"]) { | |
210 | + double di = (1.0 / elwn) * ((double)udr / 2.0); //calculate the interferogram spacing | |
211 | + double df = (double)args["spacing"].as_int(); //get the desired spectral spacing | |
212 | + n_samples = (size_t)std::ceil(1.0 / (di * df)); //calculate the number of samples required | |
213 | + std::cout << "Override default spectral spacing with " << df << " cm^(-1) by cropping to " << n_samples << " samples" << std::endl; | |
214 | + crop_samples = true; | |
215 | + } | |
216 | + | |
217 | + if (args["background"]) { | |
218 | + if (!args["fft"]) { | |
219 | + std::cout << "ERROR: using a background requires calculating an FFT - use the --fft option as well" << std::endl; | |
220 | + exit(1); | |
221 | + } | |
222 | + stim::agilent_binary<float> background(args["background"].as_string()); | |
223 | + if (background) { | |
224 | + if (crop_samples) background.crop(n_samples); //crop the samples if necessary | |
225 | + background = background.fft(wn_low, wn_high, elwn, udr); | |
226 | + save_mosaic(in, outfilename, &background); | |
227 | + //absorbance = true; | |
228 | + } | |
229 | + else { | |
230 | + std::cout << "ERROR loading background file: " << args["background"].as_string() << std::endl; | |
231 | + return 1; | |
232 | + } | |
233 | + } | |
234 | + else { | |
235 | + save_mosaic(in, outfilename); | |
236 | + } | |
237 | + | |
238 | +// _CrtDumpMemoryLeaks(); | |
239 | +} | |
0 | 240 | \ No newline at end of file | ... | ... |
1 | +++ a/src/class_ann.h | |
1 | +//OpenCV | |
2 | +#include <opencv2/opencv.hpp> | |
3 | + | |
4 | +#include "progress_thread.h" | |
5 | + | |
6 | +extern size_t X, Y, B; | |
7 | + | |
8 | +//function for training a random forest classifier | |
9 | +void train_ann(CvANN_MLP* ann, cv::Mat &trainF, cv::Mat &trainR, std::vector<int> hidden, int iters, double epsilon, bool VERBOSE = false){ | |
10 | + | |
11 | + //ANN criteria for termination | |
12 | + CvTermCriteria criter; | |
13 | + criter.max_iter = iters; | |
14 | + criter.epsilon = epsilon; | |
15 | + criter.type = CV_TERMCRIT_ITER | CV_TERMCRIT_EPS; | |
16 | + | |
17 | + //ANN parameters | |
18 | + CvANN_MLP_TrainParams params; | |
19 | + params.train_method = CvANN_MLP_TrainParams::BACKPROP; | |
20 | + params.bp_dw_scale = 0.05f; | |
21 | + params.bp_moment_scale = 0.05f; | |
22 | + params.term_crit = criter; //termination criteria | |
23 | + | |
24 | + cv::Mat layers = cv::Mat((int)hidden.size() + 2, 1, CV_32SC1); //create one input layer, one output layer, and n (specified) hidden layers | |
25 | + | |
26 | + | |
27 | + layers.row(0) = cv::Scalar(trainF.cols); //the first layer is based on the number of inputs | |
28 | + for(size_t l = 0; l < hidden.size(); l++){ //for each hidden layer | |
29 | + layers.row((int)l + 1) = cv::Scalar(hidden[l]); //specify the number of hidden nodes | |
30 | + } | |
31 | + layers.row((int)hidden.size() + 1) = cv::Scalar(trainR.cols); //the output layer is equal to the number of responses per pixel | |
32 | + | |
33 | + std::cout<<"Creating an MLP with the structure: "<<std::endl<<"\t"; | |
34 | + | |
35 | + std::cout<<"(in) "<<layers.at<int>(0, 0); | |
36 | + for(size_t l = 1; l < layers.rows - 1; l++) | |
37 | + std::cout<<" "<<layers.at<int>((int)l, 0); | |
38 | + std::cout<<" "<<layers.at<int>(layers.rows-1, 0)<<" (out)"<<std::endl; | |
39 | + ann->create(layers); //create the neural network given the architecture | |
40 | + | |
41 | + std::cout<<"Training..."<<std::endl; | |
42 | + ann->train(trainF, trainR, cv::Mat(), cv::Mat(), params); //call the ANN training algorithm | |
43 | + std::cout<<"done..."<<std::endl; | |
44 | + | |
45 | + ///// TEMPORARY - WILL BE DELETED IN THE ACTUAL IMPLEMENTATION /////////////// | |
46 | + cv::Mat predicted(trainR.rows, 1, CV_32F); //allocate space for a predicted response | |
47 | + | |
48 | + stim::image<unsigned char> test(X, Y, 3); //create a 3-channel (color) image | |
49 | + test = 0; | |
50 | + for(size_t y = 0; y < Y; y++){ //for each pixel in the image | |
51 | + for(size_t x = 0; x < X; x++){ | |
52 | + cv::Mat response(3, 1, CV_32FC1); | |
53 | + cv::Mat sample = trainF.row((int)(y * X + x)); //load the corresponding value from the training array | |
54 | + | |
55 | + ann->predict(sample, response); //predict the response for this pixel | |
56 | + test(x, y, 0) = (unsigned char)(response.at<float>(0, 0) * 255); //save the response in the color image (make sure to re-scale the values to [0, 255]) | |
57 | + test(x, y, 1) = (unsigned char)(response.at<float>(0, 1) * 255); | |
58 | + test(x, y, 2) = (unsigned char)(response.at<float>(0, 2) * 255); | |
59 | + } | |
60 | + } | |
61 | + test.save("response.bmp"); //save the response | |
62 | +} | |
0 | 63 | \ No newline at end of file | ... | ... |
1 | +++ a/src/class_bay.h | |
1 | +//OpenCV | |
2 | +#include <opencv2/opencv.hpp> | |
3 | + | |
4 | +#include "progress_thread.h" | |
5 | + | |
6 | +double progress = 0.0; | |
7 | + | |
8 | +//create a custom classifier to access the number of classes (OpenCV protected variable) | |
9 | +class BAYClass : public CvNormalBayesClassifier{ | |
10 | +public: | |
11 | + int get_nclasses(){ | |
12 | + return CvNormalBayesClassifier::cls_labels->cols; | |
13 | + } | |
14 | +}; | |
15 | + | |
16 | +/// Perform classification of the ENVI file using the current BAY classifier | |
17 | +std::vector< stim::image<unsigned char> > predict_bay(stim::envi* E, BAYClass* BAY, unsigned char* MASK = NULL){ | |
18 | + | |
19 | + size_t nC = BAY->get_nclasses(); | |
20 | + size_t X = E->header.samples; | |
21 | + size_t Y = E->header.lines; | |
22 | + size_t B = E->header.bands; | |
23 | + size_t XY = E->header.samples * E->header.lines; | |
24 | + | |
25 | + size_t tP = 0; //calculate the total number of pixels | |
26 | + if(MASK){ | |
27 | + for(size_t xy = 0; xy < XY; xy++){ | |
28 | + if(MASK[xy]) tP++; | |
29 | + } | |
30 | + } | |
31 | + else | |
32 | + tP = X * Y; | |
33 | + | |
34 | + std::vector< stim::image<unsigned char> > C; //create an array of mask images | |
35 | + C.resize(nC); | |
36 | + | |
37 | + for(unsigned long long c = 0; c < nC; c++){ //for each class mask | |
38 | + C[c] = stim::image<unsigned char>(X, Y, 1); //allocate space for the mask | |
39 | + C[c] = 0; //initialize all of the pixels to zero | |
40 | + } | |
41 | + | |
42 | + cv::Mat classF(1, (int)B, CV_32FC1); //allocate space for a single feature vector | |
43 | + | |
44 | + | |
45 | + //double progress = 0; //initialize the progress bar variable | |
46 | + std::thread t1(progressbar_thread, &progress); //start the progress bar thread | |
47 | + | |
48 | + unsigned long long t = 0; | |
49 | + for(unsigned long long p = 0; p < XY; p++){ //for each pixel | |
50 | + if(!MASK || MASK[p] > 0){ | |
51 | + E->spectrum<float>((float*)classF.data, (int)p); //fill the classF matrix with a single spectrum | |
52 | + float c = BAY->predict(classF); //classify the feature vector | |
53 | + if((size_t)c < C.size()) //if the class returned is valid | |
54 | + C[(size_t)c].data()[p] = 255; //write a white pixel to the appropriate class image | |
55 | + t++; | |
56 | + progress = (double)(t+1) / (double)(tP) * 100.0; //update the progress bar variable | |
57 | + } | |
58 | + } | |
59 | + t1.join(); //finish the progress bar thread | |
60 | + | |
61 | + return C; | |
62 | +} | |
63 | + | |
64 | +//function for training a bayesian classifier | |
65 | +void train_bay(BAYClass* BAY, cv::Mat &trainF, cv::Mat &trainR, bool VERBOSE = false){ | |
66 | + | |
67 | + unsigned tP = trainF.cols; //calculate the number of individual measurements | |
68 | + | |
69 | + if(VERBOSE) std::cout<<"Starting OpenCV CvBAY training algorithm..."; | |
70 | + BAY->train(trainF, trainR); //train the classifier | |
71 | + if(VERBOSE) std::cout<<"done"<<std::endl; | |
72 | +} | |
0 | 73 | \ No newline at end of file | ... | ... |
1 | +++ a/src/class_gmm.h | |
1 | +//OpenCV | |
2 | +#include <opencv2/opencv.hpp> | |
3 | +#include <stim/math/matrix.h> | |
4 | +#include <stim/math/constants.h> | |
5 | +#include <sstream> | |
6 | +#include "progress_thread.h" | |
7 | +#include <limits> | |
8 | +#include <chrono> | |
9 | + | |
10 | +//LAPACKE support for Visual Studio | |
11 | +#include <complex> | |
12 | +#ifndef LAPACK_COMPLEX_CUSTOM | |
13 | +#define LAPACK_COMPLEX_CUSTOM | |
14 | +#define lapack_complex_float std::complex<float> | |
15 | +#define lapack_complex_double std::complex<double> | |
16 | +#endif | |
17 | +#include "lapacke.h" | |
18 | + | |
19 | +class stim_EM : public cv::EM{ | |
20 | +public: | |
21 | + cv::vector<cv::Mat> getCovs() { | |
22 | + return covs; | |
23 | + } | |
24 | + | |
25 | + stim_EM(int nclusters = EM::DEFAULT_NCLUSTERS, int covMatType = EM::COV_MAT_DIAGONAL, | |
26 | + const cv::TermCriteria& termCrit = cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, | |
27 | + EM::DEFAULT_MAX_ITERS, FLT_EPSILON)) : cv::EM(nclusters, covMatType, termCrit) { | |
28 | + | |
29 | + } | |
30 | +}; | |
31 | + | |
32 | +//define a structure for a multi-class GMM | |
33 | +class GMM{ | |
34 | +public: | |
35 | + size_t K; //number of Gaussians per class | |
36 | + size_t F; //number of features | |
37 | + double t_gauss; | |
38 | + | |
39 | + std::vector< double > w; //array of K weights for each Gaussian | |
40 | + std::vector< stim::matrix< double > > mu; //a vector storing K mean vectors of length F | |
41 | + //std::vector< std::vector< gmm_mat > > sigma; //(C x K) array of covariance matrices (F x F) | |
42 | + std::vector< stim::matrix<double> > sigma; //array of K (F x F) covariance matrices for each Gaussian | |
43 | + std::vector< stim::matrix<double> > sigma_i; //stores the inverse covariance matrices | |
44 | + std::vector< double > sqrt_tau_sigma_det; //stores sqrt(2*pi*|sigma|) | |
45 | + | |
46 | + void init(){ | |
47 | + w.resize(K); //allocate space for weights | |
48 | + mu.resize(K); //allocate space for means | |
49 | + sigma.resize(K); //allocate space for each covariance matrix | |
50 | + for (size_t k = 0; k < K; k++) { | |
51 | + mu[k] = stim::matrix<double>(F, 1); | |
52 | + sigma[k] = stim::matrix<double>(F, F); | |
53 | + } | |
54 | + t_gauss = 0; | |
55 | + } | |
56 | + | |
57 | + //calculate the inverse sigma matrices | |
58 | + void invert_sigmas() { | |
59 | + sigma_i.resize(K); //allocate space for K inverse matrices | |
60 | + int *IPIV = (int*)malloc(sizeof(int) * F); //allocate space for the row indices | |
61 | + for (size_t k = 0; k < K; k++) { //for each sigma matrix | |
62 | + sigma_i[k] = sigma[k]; //copy the covariance matrix | |
63 | + LAPACKE_dgetrf(LAPACK_COL_MAJOR, (int)F, (int)F, sigma_i[k].data(), (int)F, IPIV); //perform LU factorization | |
64 | + LAPACKE_dgetri(LAPACK_COL_MAJOR, (int)F, sigma_i[k].data(), (int)F, IPIV); //calculate matrix inverse | |
65 | + } | |
66 | + free(IPIV); | |
67 | + } | |
68 | + | |
69 | + void calc_sqrt_tau_sigma_det() { | |
70 | + sqrt_tau_sigma_det.resize(K); | |
71 | + for (size_t k = 0; k < K; k++) { | |
72 | + sqrt_tau_sigma_det[k] = sqrt(sigma[k].det() * stim::TAU); | |
73 | + } | |
74 | + } | |
75 | + | |
76 | + //initialize predictors for improving calculation of responses | |
77 | + void init_predictors() { | |
78 | + invert_sigmas(); | |
79 | + calc_sqrt_tau_sigma_det(); | |
80 | + } | |
81 | + | |
82 | + //calculate the value of a multi-variate gaussian distribution given a vector of means and a covariance matrix | |
83 | + double mvgauss(stim::matrix<double> x, size_t k) { | |
84 | + std::chrono::high_resolution_clock::time_point t0 = std::chrono::high_resolution_clock::now(); | |
85 | + stim::matrix<double> xmu = x - mu[k]; | |
86 | + stim::matrix<double> xmu_t = xmu.transpose(); | |
87 | + stim::matrix<double> xmu_t_sigma_i = xmu_t * sigma_i[k]; | |
88 | + stim::matrix<double> xmu_t_sigma_i_xmu = xmu_t_sigma_i * xmu; | |
89 | + double a = -0.5 * xmu_t_sigma_i_xmu(0, 0); | |
90 | + double numer = exp(a); | |
91 | + stim::matrix<double> tau_sigma = sigma[k] * stim::TAU; | |
92 | + double determinant = tau_sigma.det(); | |
93 | + double denom = sqrt(determinant); | |
94 | + | |
95 | + std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); | |
96 | + t_gauss += std::chrono::duration_cast< std::chrono::duration<double> >(t1 - t0).count(); | |
97 | + return numer / denom; | |
98 | + } | |
99 | + | |
100 | + double mvgauss(double* x, size_t k, double* scratch) { | |
101 | + std::chrono::high_resolution_clock::time_point t0 = std::chrono::high_resolution_clock::now(); | |
102 | + for (size_t f = 0; f < F; f++) | |
103 | + scratch[f] = x[f] - mu[k](f, 0); | |
104 | + stim::matrix<double> xmu(F, 1, scratch); | |
105 | + stim::matrix<double> xmu_t(1, F, scratch); | |
106 | + stim::matrix<double> xmu_t_sigma_i = xmu_t * sigma_i[k]; | |
107 | + stim::matrix<double> xmu_t_sigma_i_xmu = xmu_t_sigma_i * xmu; | |
108 | + double a = -0.5 * xmu_t_sigma_i_xmu(0, 0); | |
109 | + double numer = exp(a); | |
110 | + | |
111 | + std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); | |
112 | + t_gauss += std::chrono::duration_cast< std::chrono::duration<double> >(t1 - t0).count(); | |
113 | + | |
114 | + return numer / sqrt_tau_sigma_det[k]; | |
115 | + } | |
116 | + | |
117 | + /// returns the probability density of the membership of v in all K clusters | |
118 | + std::vector<double> G(stim::matrix<double> x) { | |
119 | + std::vector<double> result(K); //allocate space for all K probabilities | |
120 | + for (size_t k = 0; k < K; k++) { //for each gaussian | |
121 | + result[k] = mvgauss(x, k); | |
122 | + } | |
123 | + return result; | |
124 | + } | |
125 | + | |
126 | + /// Calculate the response to x among all K clusters given pointers to pre-allocated arrays | |
127 | + void G(double* x, double* r) { | |
128 | + double* scratch = (double*)malloc(F * sizeof(double)); | |
129 | + for (size_t k = 0; k < K; k++) { //for each gaussian | |
130 | + r[k] = mvgauss(x, k, scratch); | |
131 | + } | |
132 | + free(scratch); | |
133 | + } | |
134 | + | |
135 | + /// Return the cluster most closely corresponding to the input vector x | |
136 | + size_t get_cluster(stim::matrix<double> x) { | |
137 | + size_t cluster; //stores the cluster ID | |
138 | + std::vector<double> posteriors = G(x); | |
139 | + double largest = posteriors[0]; | |
140 | + for (size_t k = 0; k < K; k++) { | |
141 | + if (posteriors[k] >= largest) { | |
142 | + largest = posteriors[k]; | |
143 | + cluster = k; | |
144 | + } | |
145 | + } | |
146 | + return cluster; | |
147 | + } | |
148 | + | |
149 | + ///Return the posterior probability of the vector x based on the current Gaussian mixture model | |
150 | + double P(stim::matrix<double> x) { | |
151 | + std::vector<double> posteriors = G(x); | |
152 | + double p = 0; | |
153 | + for (size_t k = 0; k < K; k++) { | |
154 | + p += w[k] * posteriors[k]; //calculate the weighted sum of all Gaussian functions | |
155 | + } | |
156 | + return p; | |
157 | + } | |
158 | + | |
159 | + double P(double* x) { | |
160 | + double* posteriors = (double*)malloc(K * sizeof(double)); | |
161 | + G(x, posteriors); | |
162 | + double p = 0; | |
163 | + for (size_t k = 0; k < K; k++) { | |
164 | + p += w[k] * posteriors[k]; //calculate the weighted sum of all Gaussian functions | |
165 | + } | |
166 | + return p; | |
167 | + } | |
168 | + | |
169 | +public: | |
170 | + | |
171 | + GMM() { | |
172 | + K = 0; | |
173 | + F = 0; | |
174 | + } | |
175 | + | |
176 | + GMM(size_t clusters, size_t features){ | |
177 | + K = clusters; | |
178 | + F = features; | |
179 | + init(); | |
180 | + } | |
181 | + | |
182 | + void set(const cv::Mat weights, const cv::Mat means, const std::vector<cv::Mat> cov) { | |
183 | + for (size_t k = 0; k < K; k++) | |
184 | + w[k] = weights.at<double>(0, (int)k); | |
185 | + | |
186 | + for (size_t k = 0; k < K; k++) | |
187 | + for (size_t f = 0; f < F; f++) | |
188 | + mu[k](f, 0) = means.at<double>((int)k, (int)f); | |
189 | + | |
190 | + for (size_t k = 0; k < K; k++) { | |
191 | + for (size_t fi = 0; fi < F; fi++) { | |
192 | + for (size_t fj = 0; fj < F; fj++) { | |
193 | + sigma[k](fi, fj) = cov[k].at<double>((int)fi, (int)fj); | |
194 | + } | |
195 | + } | |
196 | + } | |
197 | + init_predictors(); //calculate the inverse covariance matrices | |
198 | + } | |
199 | + | |
200 | + std::string str() { | |
201 | + std::stringstream ss; | |
202 | + ss << "weights:" << std::endl; | |
203 | + for (size_t k = 0; k < K; k++) | |
204 | + ss << " " << w[k] << std::endl; | |
205 | + | |
206 | + ss << std::endl << "centers:" << std::endl; | |
207 | + for (size_t k = 0; k < K; k++) | |
208 | + ss << mu[k].toStr() << std::endl; | |
209 | + | |
210 | + ss << std::endl << "covariances:" << std::endl; | |
211 | + for (size_t k = 0; k < K; k++) | |
212 | + ss << sigma[k].toStr() << std::endl; | |
213 | + return ss.str(); | |
214 | + } | |
215 | + | |
216 | + void save(std::ostream& out) { | |
217 | + out << K << std::endl; //save the number of clusters | |
218 | + out << F << std::endl; //save the number of features | |
219 | + for (size_t k = 0; k < K; k++) | |
220 | + out << std::fixed << w[k] << std::endl; | |
221 | + for (size_t k = 0; k < K; k++) | |
222 | + out << mu[k].csv() << std::endl; | |
223 | + | |
224 | + for (size_t k = 0; k < K; k++) | |
225 | + out << sigma[k].csv() << std::endl; | |
226 | + } | |
227 | + | |
228 | + void save(std::string filename) { | |
229 | + std::ofstream outfile(filename); | |
230 | + int digits = std::numeric_limits<double>::max_digits10; | |
231 | + outfile.precision(digits); | |
232 | + save(outfile); | |
233 | + outfile.close(); | |
234 | + } | |
235 | + | |
236 | + //load a GMM | |
237 | + void load(std::istream& in) { | |
238 | + in >> K; //load the number of clusters | |
239 | + in >> F; //load the number of features | |
240 | + init(); | |
241 | + for (size_t k = 0; k < K; k++) | |
242 | + in >> w[k]; | |
243 | + for (size_t k = 0; k < K; k++) | |
244 | + mu[k].csv(in); | |
245 | + | |
246 | + for (size_t k = 0; k < K; k++) | |
247 | + sigma[k].csv(in); | |
248 | + init_predictors(); //calculate the inverse covariance matrices | |
249 | + } | |
250 | + | |
251 | + void load(std::string filename) { | |
252 | + std::ifstream infile(filename); | |
253 | + load(infile); | |
254 | + infile.close(); | |
255 | + } | |
256 | + | |
257 | +}; | |
258 | + | |
259 | +/// Multi-class supervised GMM | |
260 | +class multiGMM { | |
261 | +public: | |
262 | + size_t C; //number of classes | |
263 | + | |
264 | + std::vector<GMM> gmms; //vector of Gaussian Mixture models | |
265 | + | |
266 | + /// Generate an empty GMM for each class | |
267 | + void init() { | |
268 | + for (size_t c = 0; c < C; c++) { | |
269 | + gmms.resize(C); | |
270 | + } | |
271 | + } | |
272 | + | |
273 | + multiGMM(size_t classes) { | |
274 | + C = classes; //store the number of classes | |
275 | + init(); | |
276 | + } | |
277 | + | |
278 | + //get the class that most likely corresponds to x | |
279 | + size_t get_class(stim::matrix<double> x) { | |
280 | + | |
281 | + double p0; | |
282 | + size_t c_p = 0; //stores the most likely class label | |
283 | + double p = gmms[0].P(x); //get the posterior probability of class 0 | |
284 | + for (size_t c = 1; c < C; c++) { //for each class | |
285 | + p0 = gmms[c].P(x); //get the posterior probability of membership given x | |
286 | + if (p0 > p) { //if the new class is most likely | |
287 | + p = p0; //update the maximum probability | |
288 | + c_p = c; //update the class ID | |
289 | + } | |
290 | + } | |
291 | + return c_p; | |
292 | + } | |
293 | + | |
294 | + void save(std::string filename) { | |
295 | + std::ofstream outfile(filename); //open an output file stream | |
296 | + if (outfile) { | |
297 | + int digits = std::numeric_limits<double>::max_digits10; | |
298 | + outfile.precision(digits); | |
299 | + outfile << C << std::endl; //save the number of classes | |
300 | + for (size_t c = 0; c < C; c++) { | |
301 | + gmms[c].save(outfile); //save each individual GMM | |
302 | + } | |
303 | + outfile.close(); | |
304 | + } | |
305 | + else { | |
306 | + std::cout << "ERROR creating GMM file " << filename << std::endl; | |
307 | + exit(1); | |
308 | + } | |
309 | + } | |
310 | + | |
311 | + bool load(std::string filename) { | |
312 | + std::ifstream infile(filename); //open the input file | |
313 | + if (!infile) return false; | |
314 | + infile >> C; //load the number of classes | |
315 | + gmms.resize(C); //resize the GMM array to match the number of classes | |
316 | + | |
317 | + for (size_t c = 0; c < C; c++) //load each GMM (one per class) | |
318 | + gmms[c].load(infile); | |
319 | + return true; | |
320 | + } | |
321 | +}; | |
322 | + | |
323 | +/// trains a single Gaussian Mixture model using expectation maximization in OpenCV | |
324 | +GMM train_gmm(cv::Mat &F, int k, int attempts, int iters, double epsilon){ | |
325 | + | |
326 | + GMM new_gmm(k, F.cols); //create a new GMM classifier | |
327 | + stim_EM em(k, cv::EM::COV_MAT_DIAGONAL, cv::TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, iters, epsilon)); | |
328 | + if(!em.train(F)) { | |
329 | + std::cout << "ERROR training GMM" << std::endl; | |
330 | + exit(1); | |
331 | + } | |
332 | + size_t nc = em.get<int>("nclusters"); | |
333 | + | |
334 | + cv::Mat output; | |
335 | + cv::Mat means = em.get<cv::Mat>("means"); | |
336 | + cv::Mat weights = em.get<cv::Mat>("weights"); | |
337 | + cv::vector<cv::Mat> covs = em.getCovs(); | |
338 | + new_gmm.set(weights, means, covs); | |
339 | + return new_gmm; | |
340 | +} | |
341 | + | |
342 | +//Predict a set of classes based on given centroid vectors | |
343 | +std::vector< stim::image<unsigned char> > predict_gmm(stim::envi* E, multiGMM* gmm, std::vector< stim::image<float> >& responses, unsigned char* MASK = NULL){ | |
344 | + size_t nC = gmm->C; //get the number of classes | |
345 | + if (nC == 1) | |
346 | + nC = gmm->gmms[0].K; //if there is only one GMM, classify based on clusters | |
347 | + size_t X = E->header.samples; //store ENVI file size parameters | |
348 | + size_t Y = E->header.lines; | |
349 | + size_t B = E->header.bands; | |
350 | + size_t XY = E->header.samples * E->header.lines; | |
351 | + | |
352 | + size_t tP = 0; //calculate the total number of pixels | |
353 | + if(MASK){ | |
354 | + for(size_t xy = 0; xy < XY; xy++){ | |
355 | + if(MASK[xy]) tP++; | |
356 | + } | |
357 | + } | |
358 | + else | |
359 | + tP = X * Y; | |
360 | + | |
361 | + std::vector< stim::image<unsigned char> > C; //create an array of mask images | |
362 | + C.resize(nC); | |
363 | + responses.resize(nC); //allocate space for the response images | |
364 | + | |
365 | + for(size_t c = 0; c < nC; c++){ //for each class mask | |
366 | + C[c] = stim::image<unsigned char>(X, Y, 1); //allocate space for the mask | |
367 | + memset(C[c].data(), 0, X * Y * sizeof(unsigned char)); //initialize all of the pixels to zero | |
368 | + responses[c] = stim::image<float>(X, Y, 1); //allocate space for the response image | |
369 | + memset(responses[c].data(), 0, X * Y * sizeof(float)); //initialize the response image to zero | |
370 | + } | |
371 | + | |
372 | + double progress = 0; //initialize the progress bar variable | |
373 | + std::thread t1(progressbar_thread, &progress); //start the progress bar thread | |
374 | + | |
375 | + size_t t = 0; | |
376 | + double* spectrum = (double*)malloc(sizeof(double) * B); //allocate space to hold a spectrum | |
377 | + double gm, maxgm; | |
378 | + size_t maxc; | |
379 | + for(size_t p = 0; p < XY; p++){ //for each pixel | |
380 | + if(!MASK || MASK[p] > 0){ | |
381 | + E->spectrum<double>(spectrum, p); //get the spectrum at pixel p | |
382 | + maxc = 0; | |
383 | + for (size_t c = 0; c < nC; c++) { | |
384 | + gm = gmm->gmms[c].P(spectrum); //evaluate the posterior for class c | |
385 | + responses[c].data()[p] = (float)gm; | |
386 | + | |
387 | + if (c == 0) maxgm = gm; | |
388 | + else if (gm > maxgm) { | |
389 | + maxgm = gm; | |
390 | + maxc = c; | |
391 | + } | |
392 | + } | |
393 | + C[maxc].data()[p] = 255; | |
394 | + t++; | |
395 | + progress = (double)(t+1) / (double)(tP) * 100.0; //update the progress bar variable | |
396 | + } | |
397 | + } | |
398 | + t1.join(); //finish the progress bar thread | |
399 | + | |
400 | + for (size_t c = 0; c < gmm->gmms.size(); c++) { | |
401 | + std::cout << "gauss-time (" << c << "): " << gmm->gmms[c].t_gauss << std::endl; | |
402 | + } | |
403 | + | |
404 | + return C; | |
405 | +} | |
406 | + | ... | ... |
1 | +++ a/src/class_kmeans.h | |
1 | +//OpenCV | |
2 | +#include <opencv2/opencv.hpp> | |
3 | +#include "progress_thread.h" | |
4 | + | |
5 | +/// Calculates the squared Euclidean distance between two vectors | |
6 | +template<typename T> | |
7 | +T l2_norm_sq(T* v, size_t len){ | |
8 | + T sq_sum = 0; //initialize the squared sum to zero | |
9 | + for(size_t i = 0; i < len; i++) //for each element of the vectors | |
10 | + sq_sum += pow(v[i], 2); //multiply the components | |
11 | + return sq_sum; //return the square root of the squared sum | |
12 | +} | |
13 | + | |
14 | +template<typename T> | |
15 | +T euclidean_dist_sq(T* v0, T* v1, size_t len){ | |
16 | + T* diff = (T*)malloc(sizeof(T) * len); //allocate space for the difference vector | |
17 | + for(size_t i = 0; i < len; i++) | |
18 | + diff[i] = v1[i] - v0[i]; | |
19 | + return l2_norm_sq(diff, len); | |
20 | +} | |
21 | + | |
22 | +void train_kmeans(cv::Mat ¢ers, cv::Mat &F, int k, int attempts, int iters, double epsilon){ | |
23 | + cv::Mat labels; | |
24 | + | |
25 | + cv::kmeans(F, k, labels, cv::TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, iters, epsilon), attempts, cv::KMEANS_PP_CENTERS, centers); | |
26 | + | |
27 | + int* nk = (int*) malloc(sizeof(int) * k); //create an array to store the number of pixels for each cluster | |
28 | + memset(nk, 0, sizeof(int) * k); | |
29 | + std::cout<<"size: "<<labels.size()<<std::endl; | |
30 | + for(int n = 0; n < labels.size().height; n++) | |
31 | + nk[labels.at<int>(n, 0)]++; | |
32 | + | |
33 | + for(int n = 0; n < k; n++) //for each cluster | |
34 | + std::cout<<"cluster "<<n<<" = "<<nk[n]<<std::endl; //output the number of pixels in that cluster | |
35 | + std::cout<<"total = "<<labels.rows<<std::endl; //also output the total number of pixels clustered | |
36 | +} | |
37 | + | |
38 | + | |
39 | + | |
40 | +//Predict a set of classes based on given centroid vectors | |
41 | +template<typename T> | |
42 | +std::vector< stim::image<unsigned char> > predict_centroids(stim::envi* E, std::vector< std::vector<T> > centroids, unsigned char* MASK = NULL){ | |
43 | + size_t nC = centroids.size(); //get the number of classes | |
44 | + size_t X = E->header.samples; | |
45 | + size_t Y = E->header.lines; | |
46 | + size_t B = E->header.bands; | |
47 | + size_t XY = E->header.samples * E->header.lines; | |
48 | + | |
49 | + size_t tP = 0; //calculate the total number of pixels | |
50 | + if(MASK){ | |
51 | + for(size_t xy = 0; xy < XY; xy++){ | |
52 | + if(MASK[xy]) tP++; | |
53 | + } | |
54 | + } | |
55 | + else | |
56 | + tP = X * Y; | |
57 | + | |
58 | + std::vector< stim::image<unsigned char> > C; //create an array of mask images | |
59 | + C.resize(nC); | |
60 | + | |
61 | + for(size_t c = 0; c < nC; c++){ //for each class mask | |
62 | + C[c] = stim::image<unsigned char>(X, Y, 1); //allocate space for the mask | |
63 | + memset(C[c].data(), 0, X * Y * sizeof(unsigned char)); //initialize all of the pixels to zero | |
64 | + } | |
65 | + | |
66 | + double progress = 0; //initialize the progress bar variable | |
67 | + std::thread t1(progressbar_thread, &progress); //start the progress bar thread | |
68 | + | |
69 | + size_t t = 0; | |
70 | + T* spectrum = (T*)malloc(sizeof(T) * B); //allocate space to hold a spectrum | |
71 | + double min_dist, new_dist; | |
72 | + int nearest_centroid; | |
73 | + for(unsigned long long p = 0; p < XY; p++){ //for each pixel | |
74 | + if(!MASK || MASK[p] > 0){ | |
75 | + E->spectrum<T>(spectrum, p); //get the spectrum at pixel p | |
76 | + | |
77 | + min_dist = euclidean_dist_sq<T>(centroids[0].data(), spectrum, B); //set the minimum distance as the distance to the first centroid | |
78 | + nearest_centroid = 0; //set the nearest centroid to the first centroid | |
79 | + for(size_t c = 1; c < nC; c++){ //for each centroid | |
80 | + new_dist = euclidean_dist_sq<T>(centroids[c].data(), spectrum, B); //calculate the distance to the current centroid | |
81 | + if(new_dist < min_dist){ //if the current distance is smaller | |
82 | + min_dist = new_dist; //update the minimum distance | |
83 | + nearest_centroid = (int)c; //set the nearest centroid to the current centroid | |
84 | + } | |
85 | + } | |
86 | + C[nearest_centroid].data()[p] = 255; //write a white pixel to the appropriate class image | |
87 | + t++; | |
88 | + progress = (double)(t+1) / (double)(tP) * 100.0; //update the progress bar variable | |
89 | + } | |
90 | + } | |
91 | + t1.join(); //finish the progress bar thread | |
92 | + | |
93 | + return C; | |
94 | +} | |
95 | + | ... | ... |
1 | +++ a/src/class_rf.h | |
1 | +//OpenCV | |
2 | +#include <opencv2/opencv.hpp> | |
3 | + | |
4 | +#include "progress_thread.h" | |
5 | + | |
6 | +//create a custom classifier to access the number of classes (OpenCV protected variable) | |
7 | +class RFClass : public CvRTrees{ | |
8 | +public: | |
9 | + int get_nclasses(){ return CvRTrees::nclasses;} | |
10 | +}; | |
11 | + | |
12 | +/// Perform classification of the ENVI file using the current RF classifier | |
13 | +std::vector< stim::image<unsigned char> > predict_rf(stim::envi* E, RFClass* RF, unsigned char* MASK = NULL){ | |
14 | + | |
15 | + size_t nC = RF->get_nclasses(); //get the number of classes | |
16 | + size_t X = E->header.samples; | |
17 | + size_t Y = E->header.lines; | |
18 | + size_t B = E->header.bands; | |
19 | + size_t XY = E->header.samples * E->header.lines; | |
20 | + | |
21 | + size_t tP = 0; //calculate the total number of pixels | |
22 | + if(MASK){ | |
23 | + for(size_t xy = 0; xy < XY; xy++){ | |
24 | + if(MASK[xy]) tP++; | |
25 | + } | |
26 | + } | |
27 | + else | |
28 | + tP = X * Y; | |
29 | + | |
30 | + std::vector< stim::image<unsigned char> > C; //create an array of mask images | |
31 | + C.resize(nC); | |
32 | + | |
33 | + for(unsigned long long c = 0; c < nC; c++){ //for each class mask | |
34 | + C[c] = stim::image<unsigned char>(X, Y, 1); //allocate space for the mask | |
35 | + memset(C[c].data(), 0, X * Y * sizeof(unsigned char)); //initialize all of the pixels to zero | |
36 | + } | |
37 | + | |
38 | + cv::Mat classF(1, (int)B, CV_32FC1); //allocate space for a single feature vector | |
39 | + | |
40 | + | |
41 | + double progress = 0; //initialize the progress bar variable | |
42 | + std::thread t1(progressbar_thread, &progress); //start the progress bar thread | |
43 | + | |
44 | + unsigned long long t = 0; | |
45 | + for(unsigned long long p = 0; p < XY; p++){ //for each pixel | |
46 | + if(!MASK || MASK[p] > 0){ | |
47 | + E->spectrum<float>((float*)classF.data, (int)p); //fill the classF matrix with a single spectrum | |
48 | + float c = RF->predict(classF); //classify the feature vector | |
49 | + C[(size_t)c].data()[p] = 255; //write a white pixel to the appropriate class image | |
50 | + t++; | |
51 | + progress = (double)(t+1) / (double)(tP) * 100.0; //update the progress bar variable | |
52 | + } | |
53 | + } | |
54 | + t1.join(); //finish the progress bar thread | |
55 | + | |
56 | + return C; | |
57 | +} | |
58 | + | |
59 | +//function for training a random forest classifier | |
60 | +void train_rf(RFClass* RF, cv::Mat &trainF, cv::Mat &trainR, int tree_depth, int num_trees, bool VERBOSE = false){ | |
61 | + | |
62 | + //unsigned tP = trainF.cols; //calculate the number of individual measurements | |
63 | + | |
64 | + CvRTParams params( tree_depth, // max_depth, | |
65 | + 1, // min_sample_count, | |
66 | + 0.f, // regression_accuracy, | |
67 | + false, // use_surrogates, | |
68 | + 16, // max_categories, | |
69 | + 0, // priors, | |
70 | + false, // calc_var_importance, | |
71 | + 0, // nactive_vars, | |
72 | + num_trees, // max_num_of_trees_in_the_forest, | |
73 | + 0, // forest_accuracy, | |
74 | + CV_TERMCRIT_ITER // termcrit_type | |
75 | + ); | |
76 | + | |
77 | + if(VERBOSE) std::cout<<"Starting OpenCV CvRT training algorithm..."; | |
78 | + RF->train(trainF, CV_ROW_SAMPLE, trainR, cv::Mat(), cv::Mat(), cv::Mat(), cv::Mat(), params ); //train the classifier | |
79 | + if(VERBOSE) std::cout<<"done"<<std::endl; | |
80 | +} | |
0 | 81 | \ No newline at end of file | ... | ... |
1 | +++ a/src/mask_manipulation.h | |
1 | +#ifndef MASK_MANIPULATION | |
2 | +#define MASK_MANIPULATION | |
3 | + | |
4 | +#include <numeric> | |
5 | + | |
6 | +#include <stim/image/image.h> | |
7 | + | |
8 | +///This file contains functions designed to process, subsample, and manipulate masks images | |
9 | + | |
10 | +void push_training_image(std::vector< stim::image<unsigned char> >& C, std::vector<size_t>& nP, size_t& tP, stim::image<unsigned char> I) { | |
11 | + C.push_back(I); | |
12 | + size_t npixels = I.nnz(); | |
13 | + nP.push_back(npixels); //push the number of pixels onto the pixel array | |
14 | + tP += npixels; //add to the running total of pixels | |
15 | +// nC++; | |
16 | +} | |
17 | + | |
18 | +//re-calculates the total number of pixels in an image list | |
19 | +size_t calc_tP(std::vector< stim::image<unsigned char> >& C, std::vector< size_t > nP) { | |
20 | + size_t tP = 0; | |
21 | + for (size_t i = 0; i < C.size(); i++) { | |
22 | + tP += nP[i]; | |
23 | + } | |
24 | + return tP; | |
25 | +} | |
26 | + | |
27 | +size_t calc_tP(std::vector< stim::image<unsigned char> >& C) { | |
28 | + std::vector<size_t> nP(C.size()); | |
29 | + for (size_t ci = 0; ci < C.size(); ci++) | |
30 | + nP[ci] = C[ci].nnz(); | |
31 | + return calc_tP(C, nP); | |
32 | +} | |
33 | + | |
34 | +//load a mask given a mask filename | |
35 | +void AND_mask(std::vector< stim::image<unsigned char> >& C, std::vector<size_t>& nP, size_t& tP, std::string maskfile){ | |
36 | + stim::image<unsigned char> mask_image(maskfile); //load the image | |
37 | + stim::image<unsigned char> mono_image = mask_image.channel(0); //retrieve the first channel | |
38 | + | |
39 | + if(C.size() == 0){ | |
40 | + push_training_image(C, nP, tP, mono_image); | |
41 | + } | |
42 | + else{ | |
43 | + size_t N = C[0].width() * C[0].height(); //precompute the number of pixels in the mask | |
44 | + tP = 0; | |
45 | + for(size_t xy = 0; xy < N; xy++){ //for each pixel in the mask | |
46 | + if(!C.back().data()[xy] || !mono_image.data()[xy]){ //if both the current and new mask is true | |
47 | + C.back().data()[xy] = 0; | |
48 | + } | |
49 | + } | |
50 | + nP.back() = C.back().nnz(); | |
51 | + } | |
52 | + calc_tP(C, nP); | |
53 | + std::cout<<"masked pixels: "<<tP<<std::endl; | |
54 | +} | |
55 | + | |
56 | +void push_full_mask(std::vector< stim::image< unsigned char > >& C, size_t X, size_t Y) { | |
57 | + stim::image<unsigned char> img(X, Y, 1); //create an empty image | |
58 | + img = 255; //set all values to 255 | |
59 | + | |
60 | + C.push_back(img); //push the image onto the image array | |
61 | +} | |
62 | + | |
63 | +void push_fully_masked_image(std::vector< stim::image< unsigned char > >& C, std::vector<size_t>& nP, size_t& tP, size_t X, size_t Y){ | |
64 | + | |
65 | + push_full_mask(C, X, Y); | |
66 | + | |
67 | + size_t npixels = C[C.size() - 1].nnz(); | |
68 | + nP.push_back(npixels); //push the number of pixels onto the pixel array | |
69 | + tP += npixels; //add to the running total of pixels | |
70 | + //nC++; //increment the number of classes | |
71 | +} | |
72 | + | |
73 | +void subsample_masks(std::vector< stim::image<unsigned char> >&I, size_t n) { | |
74 | + size_t tP = calc_tP(I); | |
75 | + if (tP <= n) return; //if there are less than n pixels already, nothing changes | |
76 | + | |
77 | + std::vector< stim::image<unsigned char> > new_C; //create a new training image array | |
78 | + new_C.resize(I.size()); //set the correct size of the array | |
79 | + | |
80 | + std::vector<size_t> idx(tP); //create an array that will store the indices of each pixel | |
81 | + size_t ip = 0; //index into the index array | |
82 | + | |
83 | + size_t X = I[0].width(); | |
84 | + size_t Y = I[0].height(); | |
85 | + | |
86 | + for (size_t c = 0; c < I.size(); c++) { //for each training image | |
87 | + new_C[c] = stim::image<unsigned char>(X, Y, 1); //create a new image that matches the size of the original | |
88 | + new_C[c] = 0; //set all values in the image to zero | |
89 | + std::vector<size_t> c_idx = I[c].sparse_idx(); //get the indices of each non-zero pixel | |
90 | + | |
91 | + for (size_t i = 0; i < c_idx.size(); i++) { //for each index | |
92 | + idx[ip + i] = c_idx[i] + c * X * Y; //scale the index by the image number and store it in the index array | |
93 | + } | |
94 | + ip += c_idx.size(); //increment the global index | |
95 | + } | |
96 | + | |
97 | + std::random_device rd; //create a random number generation function | |
98 | + std::mt19937 g(rd()); | |
99 | + std::shuffle(idx.begin(), idx.end(), g); //shuffle the index values | |
100 | + | |
101 | + size_t c, ix; | |
102 | + for (size_t i = 0; i < n; i++) { //for each of the first n random pixels | |
103 | + c = idx[i] / (X * Y); //calculate the image that the current pixel is in | |
104 | + ix = idx[i] - c * X * Y; //calculate the 1D index of the current pixel | |
105 | + new_C[c].data()[ix] = I[c].data()[ix]; //store the value of the pixel in the new C array | |
106 | + } | |
107 | + | |
108 | + I = new_C; //replace the class image array | |
109 | +} | |
110 | + | |
111 | +/// This function picks a random set of N samples from among the training masks | |
112 | +void set_random_samples(std::vector< stim::image<unsigned char> >& C, std::vector<size_t>& nP, size_t& tP, size_t n){ | |
113 | + | |
114 | + subsample_masks(C, n); | |
115 | + | |
116 | + tP = 0; //reset the total number of pixels to zero | |
117 | + for(size_t c = 0; c < C.size(); c++){ //for each class image | |
118 | + nP[c] = C[c].nnz(); //re-calculate the number of pixels in each image | |
119 | + tP += nP[c]; //re-calculate the total number of pixels | |
120 | + } | |
121 | +} | |
122 | + | |
123 | +/// Calculate a new image composed of N random pixels from the input image | |
124 | +stim::image<unsigned char> random_subset(stim::image<unsigned char> in, size_t n) { | |
125 | + if (n >= in.nnz()) return in; //if the number of pixels requested is less than the number of masked pixels, return the original image | |
126 | + std::vector<size_t> idx = in.sparse_idx(); //get the indices of each non-zero pixel | |
127 | + std::random_device rd; //create a random number generation function | |
128 | + std::mt19937 g(rd()); | |
129 | + std::shuffle(idx.begin(), idx.end(), g); //shuffle the index values | |
130 | + | |
131 | + stim::image<unsigned char> out(in.width(), in.height(), 1); //create an output image the same size as the input image | |
132 | + out = 0; //set all pixels to zero | |
133 | + | |
134 | + for (size_t i = 0; i < n; i++) //go through each pixel index until the number of requested pixels is reached | |
135 | + out.data()[idx[i]] = 255; //set the pixel value at that location to TRUE | |
136 | + | |
137 | + return out; //return the output image | |
138 | +} | |
139 | + | |
140 | + | |
141 | +/// This function picks a random set of N samples from among the training masks. The samples are selected to make the training | |
142 | +/// set as balanced as possible (equal numbers of training samples from each class). | |
143 | +void set_random_samples_balanced(std::vector< stim::image< unsigned char > >& C, size_t n, std::string output_mask) { | |
144 | + | |
145 | + //size_t tP = calc_tP(C, nP); | |
146 | + //if (tP <= n) return; //if there are less than n pixels already, nothing changes | |
147 | + | |
148 | + std::vector< stim::image<unsigned char> > new_C; //create a new training image array | |
149 | + new_C.resize(C.size()); //set the correct size of the array | |
150 | + | |
151 | + //calculate the number of pixels in each training image | |
152 | + std::vector<size_t> num_pix_per_class(C.size()); //create a vector to store the number of pixels in each class | |
153 | + for (size_t c = 0; c < C.size(); c++) //for each class | |
154 | + num_pix_per_class[c] = C[c].nnz(); //calculate the number of pixels | |
155 | + | |
156 | + std::vector<int> c_idx(num_pix_per_class.size()); //create a vector that will store indices into the sorted class array | |
157 | + std::iota(c_idx.begin(), c_idx.end(), 0); //fill the index array with a list of indices [0, c) | |
158 | + | |
159 | + //create a function that compares two values in the num_pix_per_class array and sorts the indices | |
160 | + auto comparator = [&num_pix_per_class](int a, int b) { return num_pix_per_class[a] < num_pix_per_class[b]; }; | |
161 | + std::sort(c_idx.begin(), c_idx.end(), comparator); //sort the indices, which can be used to look up the sorted version of the number of pixels per class | |
162 | + | |
163 | + size_t ppc = n / C.size(); //calculate the ideal number of pixels per class | |
164 | + size_t pixels_used = 0; //number of pixels that have already been accepted into the mask array | |
165 | + | |
166 | + for (size_t ci = 0; ci < C.size(); ci++) { //for each class (starting with the smallest) | |
167 | + ppc = (n - pixels_used) / (C.size() - ci); //determine the number of pixels per class that have to be used to balance out the rest of the classes | |
168 | + size_t pix = C[c_idx[ci]].nnz(); //get the number of pixels in this class | |
169 | + new_C[c_idx[ci]] = random_subset(C[c_idx[ci]], ppc); //get a random subset of the class | |
170 | + pixels_used += new_C[c_idx[ci]].nnz(); //get the actual number of pixels in the subsample and use it to increment the number of pixels used in the new mask images | |
171 | + } | |
172 | + | |
173 | + C = new_C; //replace the class image array | |
174 | + | |
175 | + if (output_mask != "") { //if the user specifies a mask filename, save each subsampled image | |
176 | + stim::filename fmask = output_mask; //create a file name object from the mask string | |
177 | + for (size_t c = 0; c < C.size(); c++) { | |
178 | + stim::filename f = fmask.insert(c, 4); //generate a numbered file name | |
179 | + C[c].save(f.str()); //convert the file name to a string and save the image | |
180 | + } | |
181 | + } | |
182 | + | |
183 | + /*//tP = 0; //reset the total number of pixels to zero | |
184 | + for (size_t c = 0; c < C.size(); c++) { //for each class image | |
185 | + //nP[c] = C[c].nnz(); //re-calculate the number of pixels in each image | |
186 | + //tP += nP[c]; //re-calculate the total number of pixels | |
187 | + if (maskfile != "") { | |
188 | + std::stringstream ss; | |
189 | + ss << "resample_class_" << c << ".bmp"; | |
190 | + C[c].save(ss.str()); | |
191 | + } | |
192 | + }*/ | |
193 | +} | |
194 | + | |
195 | + | |
196 | +#endif | |
0 | 197 | \ No newline at end of file | ... | ... |
1 | +++ a/src/proc/bandimage.cpp | |
1 | +#define NOMINMAX | |
2 | +#include "stim/visualization/colormap.h" | |
3 | +#include "stim/envi/envi.h" | |
4 | +#include "stim/parser/filename.h" | |
5 | +#include <thread> | |
6 | + | |
7 | +extern stim::envi ENVI; | |
8 | +void progress_thread_envi(stim::envi* e); //progress bar threaded function | |
9 | +extern unsigned long long X, Y, B; | |
10 | + | |
11 | +//converts a string to a colormap | |
12 | +stim::colormapType str2cmap(std::string str){ | |
13 | + if(str == "brewer") return stim::cmBrewer; | |
14 | + else if(str == "grey" || str == "gray") return stim::cmGrayscale; | |
15 | + else{ | |
16 | + std::cout<<"Invalid color map specified"<<std::endl; | |
17 | + exit(1); | |
18 | + } | |
19 | +} | |
20 | + | |
21 | +void bandimage(std::string infile, std::string headername, double band, std::string filename, double minVal, double maxVal, stim::colormapType cmap = stim::cmBrewer, unsigned char* MASK = NULL){ | |
22 | + | |
23 | + std::cout<<"Generating an image of "<<infile<<" at band "<<band<<"..."<<std::endl; | |
24 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
25 | + | |
26 | + if(ENVI.header.data_type == stim::envi_header::float32){ | |
27 | + float* image = (float*)malloc(sizeof(float) * X * Y); | |
28 | + ENVI.band(image, band, true); | |
29 | + | |
30 | + stim::filename f(filename); //create a stim::filename | |
31 | + if(f.extension() == "" || f.extension() == "raw"){ //if there is no extension or the extension is "raw" | |
32 | + std::ofstream outfile(filename, std::ios::binary); //open the file for binary writing | |
33 | + outfile.write((char*)image, X * Y * sizeof(float)); //write the data | |
34 | + outfile.close(); | |
35 | + } | |
36 | + else | |
37 | + stim::cpu2image<float>(image, filename, X, Y, (float)minVal, (float)maxVal, cmap); //convert band image to a picture and save | |
38 | + free(image); | |
39 | + } | |
40 | + else{ | |
41 | + std::cout<<"ERROR: only float binary files are workable"<<std::endl; | |
42 | + } | |
43 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
44 | +} | |
45 | + | |
46 | +/// Generate a band | |
47 | +void bandimage(std::string infile, std::string headername, double band, std::string filename, stim::colormapType cmap, unsigned char* MASK = NULL){ | |
48 | + | |
49 | + | |
50 | + std::cout<<"Generating an image at "<<band<<" "<<ENVI.header.wavelength_units<<std::endl; | |
51 | + std::cout<<" the band range of the input file is ["; | |
52 | + if (ENVI.header.wavelength.empty()) | |
53 | + std::cout << "0 - " << ENVI.header.bands - 1 << "] bands" << std::endl; | |
54 | + else { | |
55 | + std::cout << ENVI.header.wavelength[0] << " - " << ENVI.header.wavelength.back() << "] "; | |
56 | + if (ENVI.header.wavelength_units == "Unknown") | |
57 | + std::cout << "(Unknown Units)" << std::endl; | |
58 | + else | |
59 | + std::cout << ENVI.header.wavelength_units << std::endl; | |
60 | + } | |
61 | + | |
62 | + | |
63 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
64 | + | |
65 | + if(ENVI.header.data_type == stim::envi_header::float32){ | |
66 | + float* image = (float*)malloc(sizeof(float) * X * Y); | |
67 | + ENVI.band(image, band, true); | |
68 | + | |
69 | + float maxval = image[0]; | |
70 | + float minval = image[0]; | |
71 | + float minmag = std::numeric_limits<float>::max(); | |
72 | + for (size_t i = 0; i < X * Y; i++) { | |
73 | + if (!MASK || MASK[i]) { | |
74 | + if (image[i] > maxval) maxval = image[i]; | |
75 | + if (image[i] < minval) minval = image[i]; | |
76 | + if (abs(image[i]) < abs(minmag)) minmag = image[i]; | |
77 | + } | |
78 | + } | |
79 | + std::cout << "Saving " << X << " x " << Y << " image, with values in (" << minval << ", " << maxval << ") and |min| = " << minmag << "..." << std::endl; | |
80 | + | |
81 | + stim::filename f(filename); //create a stim::filename | |
82 | + if(f.extension() == "" || f.extension() == "raw"){ //if there is no extension or the extension is "raw" | |
83 | + std::ofstream outfile(filename, std::ios::binary); //open the file for binary writing | |
84 | + outfile.write((char*)image, X * Y * sizeof(float)); //write the data | |
85 | + outfile.close(); | |
86 | + } | |
87 | + else | |
88 | + stim::cpu2image<float>(image, filename, X, Y, cmap); //convert band image to a picture and save | |
89 | + free(image); | |
90 | + } | |
91 | + else | |
92 | + { | |
93 | + std::cout<<"ERROR: only float binary files are workable"<<std::endl; | |
94 | + } | |
95 | + | |
96 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
97 | + | |
98 | + | |
99 | +} | ... | ... |
1 | +++ a/src/proc/baseline.cpp | |
1 | +#include <iostream> | |
2 | +#include <time.h> | |
3 | +#include <thread> | |
4 | +#include "stim/envi/envi_header.h" | |
5 | +#include "stim/envi/bip.h" | |
6 | +#include "stim/envi/bil.h" | |
7 | +#include "stim/envi/bsq.h" | |
8 | +#include "stim/envi/envi.h" | |
9 | + | |
10 | +void progress_thread_envi(stim::envi* e); | |
11 | +extern stim::envi ENVI; | |
12 | + | |
13 | + | |
14 | +//perform the appropriate baseline correction, depending on file type | |
15 | +void baseline(std::string infile, std::string outfile, std::string headerfile, std::vector<double> points, unsigned char* mask){ | |
16 | + | |
17 | + std::cout<<"Performing linear baseline correction using "<<points.size()<<" points..."<<std::endl; | |
18 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
19 | + ENVI.baseline(outfile,points, mask, true); //perform baseline correction | |
20 | + //ENVI.close(); | |
21 | + | |
22 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
23 | + | |
24 | + | |
25 | +} | ... | ... |
1 | +++ a/src/proc/hsiproc.cpp | |
1 | +#include <iostream> | |
2 | +#include <fstream> | |
3 | +#include <random> | |
4 | +#include <algorithm> | |
5 | + | |
6 | +#include "stim/parser/arguments.h" | |
7 | +#include "stim/envi/envi_header.h" | |
8 | +#include "stim/envi/envi.h" | |
9 | +#include "stim/visualization/colormap.h" | |
10 | +#include <stim/image/image.h> | |
11 | +#include <stim/parser/table.h> | |
12 | +#include <stim/parser/filename.h> | |
13 | +#include <stim/envi/agilent_binary.h> | |
14 | +#include <stim/math/matrix.h> | |
15 | +#include <time.h> | |
16 | +#include <fstream> | |
17 | +#include <thread> | |
18 | + | |
19 | +//LAPACKE support for Visual Studio | |
20 | +#include <complex> | |
21 | +#ifndef LAPACK_COMPLEX_CUSTOM | |
22 | +#define LAPACK_COMPLEX_CUSTOM | |
23 | +#define lapack_complex_float std::complex<float> | |
24 | +#define lapack_complex_double std::complex<double> | |
25 | +#endif | |
26 | +#include "lapacke.h" | |
27 | +//#include "cblas.h" | |
28 | + | |
29 | +void baseline(std::string infile, std::string outfile, std::string headerfile, std::vector<double> points, unsigned char* mask); | |
30 | +void normalize(std::string infile, std::string outfile, std::string headerfile, double band, unsigned char* mask); | |
31 | +void convert(std::string infile, std::string outfile, std::string headerfile, stim::envi_header::interleaveType type); | |
32 | +std::vector< std::vector<double> > read_metric_list(std::string filename); | |
33 | +void create_metric_file(std::vector< std::vector<double> > metrics, std::string outfile); | |
34 | +stim::colormapType str2cmap(std::string str); | |
35 | +void bandimage(std::string infile, std::string headername, double band, std::string filename, stim::colormapType cmap, unsigned char* MASK); | |
36 | +void bandimage(std::string infile, std::string headername, double band, std::string filename, double minVal, double maxVal, stim::colormapType cmap, unsigned char* MASK); | |
37 | +//void mosaic_agilent(std::string directory, std::string outfile, bool create_header); | |
38 | +void mosaic_agilent_interferogram(std::string filemask, std::string outfile, double ELWN, int UDR); | |
39 | +void mosaic_spero(std::string directory, std::string outfile); | |
40 | +void mnf(std::string outfile, int keptComponents, std::string NoiseFractions, int cuda_device); | |
41 | + | |
42 | +void progress_thread_envi(stim::envi* e); //progress bar threaded function | |
43 | +void progress_thread_double(double* e); //progress bar threaded function | |
44 | + | |
45 | +//CUDA externs | |
46 | +//void gpu_bsq2bip(); | |
47 | + | |
48 | + | |
49 | +# define MAX_CLASSES 20 | |
50 | +# define per 20000 | |
51 | + | |
52 | +unsigned char* MASK = NULL; //pointer to an input file mask if one is provided | |
53 | +stim::envi ENVI; //input ENVI file to be processed | |
54 | +unsigned long long X, Y, B; //registers to quickly access the image size | |
55 | + | |
56 | +bool progressbar = true; | |
57 | +bool verbose = false; | |
58 | +bool optimization = true; | |
59 | + | |
60 | +void advertisement(){ | |
61 | + std::cout<<std::endl<<std::endl; | |
62 | + std::cout<<"========================================================================="<<std::endl; | |
63 | + std::cout<<"Thank you for using the HSIPROC spectroscopic image processing toolkit!"<<std::endl; | |
64 | + std::cout<<"Scalable Tissue Imaging and Modeling (STIM) Lab, University of Houston"<<std::endl; | |
65 | + std::cout<<"Developers: Sam Saki, Ziqi He, David Mayerich, Brad Deutsch"<<std::endl; | |
66 | + std::cout<<"Source: https://github.com/stimlab/hsiproc.git"<<std::endl; | |
67 | + std::cout << "This version has been compiled on " << __DATE__ << " at " << __TIME__ << std::endl; | |
68 | + std::cout<<"========================================================================="<<std::endl<<std::endl; | |
69 | +} | |
70 | + | |
71 | +int test(int i){ | |
72 | + std::cout<<"Thread started..."<<std::endl; | |
73 | + return i * 10; | |
74 | +} | |
75 | + | |
76 | +void set_mask(std::string filename, size_t N = 0){ | |
77 | + size_t bytes = X * Y * sizeof(unsigned char); //calculate the number of bytes in the mask | |
78 | + MASK = (unsigned char*) malloc(bytes); //allocate space for the mask | |
79 | + memset(MASK, 0, bytes); //initialize the mask to 0 (zeros) | |
80 | + std::string maskfile = filename; //mask file name | |
81 | + stim::image<unsigned char> image(maskfile); //create an image from the file | |
82 | + stim::image<unsigned char> mask = image.channel(0); //grab the first channel of the image | |
83 | + if (mask.width() != X || mask.height() != Y) { | |
84 | + std::cout << "ERROR - mask size doesn't match image size: mask = [" << mask.width() << " x " << mask.height() << "], input = [" << X << " x " << Y << "]" << std::endl; | |
85 | + exit(1); | |
86 | + } | |
87 | + if(N == 0){ //if only the mask name is given, use all pixels in the mask | |
88 | + for(size_t xy = 0; xy < X*Y; xy++) //for each pixel in the image | |
89 | + if(mask.data()[xy]) MASK[xy] = mask.data()[xy]; //copy it to the MASK pointer | |
90 | + } | |
91 | + else{ //if a number of values is also specified | |
92 | + N = (std::min)(N, mask.nnz()); //calculate the minimum (this odd notation is used to defeat a macro implemented in Visual Studio) | |
93 | + std::vector<size_t> idx = image.sparse_idx(); //get the indices for the nonzero values in the image | |
94 | + std::random_device rd; //create a random number generation function | |
95 | + std::mt19937 g(rd()); | |
96 | + std::shuffle(idx.begin(), idx.end(), g); //shuffle the index values | |
97 | + for(size_t i = 0; i < N; i++){ //for each of the first n random pixels | |
98 | + MASK[idx[i]] = mask.data()[idx[i]]; //store the pixel value from the image into the mask | |
99 | + } | |
100 | + } | |
101 | + | |
102 | +} | |
103 | + | |
104 | +int main(int argc, char** argv){ | |
105 | + | |
106 | + //create an argument list | |
107 | + stim::arglist args; | |
108 | + | |
109 | +#ifdef _WIN32 | |
110 | + args.set_ansi(false); | |
111 | +#endif | |
112 | + | |
113 | + //basic arguments | |
114 | + args.add("help", "prints this help"); | |
115 | + | |
116 | + args.section("Binary File Manipulation"); | |
117 | + args.add("convert", "convert file to bip, bsq, or bil", "", "[bsq], [bip], or [bil]"); | |
118 | + args.add("sift", "create a matrix of masked spectra in lexicographic order", "", "[mask_filename]"); | |
119 | + args.add("unsift", "creates a 2D image from a matrix of pixels in lexicographic order", "", "[mask_filename]"); | |
120 | + args.add("crop", "crop part of original file, use '-' to specify the limit, spectral coordinates are given in wavelength by default", "", "[x nx y ny w nw]"); | |
121 | + args.add("subimages", "extract a subimage at each mask point", "", "[maskfile width height], if no height is given, height = width"); | |
122 | + args.add("trim", "remove bands", "", "[b0 b1 b2-b3], removes b0, b1, and all bands between b2 and b3"); | |
123 | + args.add("select", "selects a set of bands from the input image and uses them to create a new output image", "", "list of wavelengths or bands, ex: 1250 1650 3200 ..."); | |
124 | + args.add("combine", "combines two images by placing the second at a specified position relative to the first", "", "[filename px py], if (px, py) isn't provided, combining is done along Y"); | |
125 | + args.add("append", "appends the bands from an image to the input image", "", "[filename] - the input and append file must be the same size in X and Y"); | |
126 | + | |
127 | + args.section("Arithmetic"); | |
128 | + args.add("multiply", "multiply values in the image by some number n", "", "[n] where n is any real value"); | |
129 | + args.add("add", "add values in the image by some number n", "", "any real value"); | |
130 | + | |
131 | + args.section("Data Retrieval / Analysis"); | |
132 | + args.add("image", "wavelength and filename for a band image (.raw files are X x Y float32)", "", "[wavelength] or [wavelength min max]"); | |
133 | + args.add("colormap", "specify the colormap for an image", "brewer", "brewer, grey"); | |
134 | + args.add("spectrum", "saves a CSV spectrum", "", "[x y]"); | |
135 | + args.add("mean", "saves the mean spectrum and variance (sigma^2) as a CSV file - mask can (and should) be applied"); | |
136 | + args.add("median", "saves the median spectrum as a CSV file - mask can be applied, only works for BSQ files"); | |
137 | + args.add("covariance", "calculate the covariance matrix of the spectrum and saves it as a CSV file (BIP recommended)", "", "[mean.csv], optional CSV file name storing the mean spectrum"); | |
138 | + args.add("deriv", "approximate the d-th derivative at order n (default n=2) using finite differences", "", "[d n]"); | |
139 | + | |
140 | + args.section("Convolution (assumes equally spaced points)"); | |
141 | + args.add("convolve", "convolve the spectra with a given set of coefficients", "", "[c1 c2 c3...cn]"); | |
142 | + args.add("sg", "applies a Savitzky-Golay filter of width w and order n, where w is odd and n < w/2", "", "[w n]"); | |
143 | + | |
144 | + args.section("Hyperspectral Image Correction"); | |
145 | + args.add("baseline", "piecewise linear baseline correction", "", "[baseline-file.txt] or [p0 p1 p2 p3 ...]"); | |
146 | + args.add("mnf", "Generate a basis for MNF noise removal. Use --project to apply the basis projection to a noisy file", "", "[keptComponents noisefile] , ex. --mnf 7 , in most cases: 3 < keptComponents < 23"); | |
147 | + args.add("matcond", "Specify the threshold for the MNF transform condition number c - a warning will be given if c is below this threshold.", "0.01"); | |
148 | + args.add("normalize", "normalize spectra using vector normalization (or a band ratio of a band is specified)", "", "[band]"); | |
149 | + | |
150 | + args.section("Masking"); | |
151 | + args.add("threshold", "create a mask that includes all pixel in band such that min < val < max", "", "[band min max]"); | |
152 | + args.add("mask-finite", "create a mask - all pixels without inf or NaN values are masked"); | |
153 | + args.add("apply-mask","apply a mask (or set of masks) to an image (any false value in a mask is set to 0)", "", "[image_1 image_2 image_3]"); | |
154 | + args.add("mask", "limit clustering to a masked region specified by an image file", "", "[filename n], where n (optional) limits the mask to n random samples of the image"); | |
155 | + | |
156 | + args.section("Dimension Reduction"); | |
157 | + args.add("pca", "calculate and save the PCA basis transform (BIP recommended)"); | |
158 | + args.add("project", "perform a forward projection given a translation and set of basis vectors", "", "[stats_file #vectors], ex. PCA: [pca.sta 30]"); | |
159 | + args.add("inverse", "perform an inverse projection given a translation and set of basis vectors", "", "[stats_file #vectors]"); | |
160 | + args.add("metrics", "calculate metrics based on Bhargava et al. metric file", "", "[metric_file]\n\t\t\t" | |
161 | + "metric format:\n\t\t\t" | |
162 | + "peak height ratio: \t1 LB1 RB1 P1 LB2 RB2 P2 0 0\n\t\t\t" | |
163 | + "peak area ratio: \t2 LB1 RB1 LP1 RP1 LB2 RB2 P2 0\n\t\t\t" | |
164 | + "area to area ratio: \t3 LB1 RB1 LP1 RP1 LB2 RB2 LP2 RP2\n\t\t\t" | |
165 | + "center of gravity: \t4 LB1 RB1 LP1 RP1 0 0 0 0"); | |
166 | + | |
167 | + args.section("Hardware-Specific Processing"); | |
168 | + args.add("create-header", "create a basic header file to represent the mosaic"); | |
169 | + args.section("Debugging Parameters"); | |
170 | + args.add("verbose", "provide verbose debug messages and output"); | |
171 | + args.add("noprogress", "removes the progress bar from the output"); | |
172 | + args.add("nooptimization", "turns off batch optimization, max batch size is used"); | |
173 | + args.add("mempct", "percentage of available memory to use for processing", "40", "values over 90% are not recommended"); | |
174 | + args.add("memraw", "specify a raw amount of memory (in MB) to use for processing (caution)"); | |
175 | + args.add("cuda", "selects the default CUDA device used for calculations", "0", "integer ID, (-1 prevents CUDA use even if available)"); | |
176 | + | |
177 | + //parse the command line arguments | |
178 | + args.parse(argc, argv); | |
179 | + if(args["help"].is_set()){ //display the help text if requested | |
180 | + advertisement(); | |
181 | + std::cout<<std::endl<<"usage: hsiproc input output --option [A B C ...]"<<std::endl; | |
182 | + std::cout<<std::endl<<std::endl | |
183 | + << "examples: siproc bsqfile bipfile --convert bip"<<std::endl; | |
184 | + std::cout << " convert the input file bsqfile to the output bipfile, changing the interleave from BSQ to BIP" << std::endl; | |
185 | + std::cout << " siproc bsqfile bandfile.bmp --image 1650" << std::endl; | |
186 | + std::cout << " create a bitmap image of bsqfile at wavelength 1650" << std::endl; | |
187 | + std::cout << " siproc mosaic_in mosaic_cropped --crop 1000 2000 - 1000 1500 120" << std::endl; | |
188 | + std::cout << " crop the input file mosaic_in to generate a 1000 x 1000 image spanning wavelengths 1500 to 1620" << std::endl; | |
189 | + std::cout<<std::endl<<std::endl; | |
190 | + std::cout<<args.str()<<std::endl; | |
191 | + exit(1); | |
192 | + } | |
193 | + | |
194 | + ////Address Input and Output file issues | |
195 | + //In some cases, the input and output can be inferred which means that the user doesn't HAVE | |
196 | + // to specify 2 arguments (input and output file). Check for these cases here | |
197 | + std::string infile; | |
198 | + std::string outfile; | |
199 | + | |
200 | + if(args.nargs() == 0){ //if no arguments are provided | |
201 | + advertisement(); | |
202 | + std::cout<<"ERROR: No input or output specified, enter hsiproc --help for options."<<std::endl<<std::endl; | |
203 | + return 1; | |
204 | + } | |
205 | + else if(args.nargs() == 1){ //if only one argument is available | |
206 | + std::cout<<"ERROR: missing input/output file parameter (2 are required for this algorithm)."<<std::endl; | |
207 | + return 1; | |
208 | + } | |
209 | + else{ //two (or more) arguments are available (ignore more than two) | |
210 | + infile = args.arg(0); | |
211 | + outfile = args.arg(1); | |
212 | + } | |
213 | + | |
214 | + | |
215 | + | |
216 | + //////////////// Debugging Parameters ///////////////////////////////////// | |
217 | + if(args["verbose"].is_set()){ | |
218 | + verbose = true; | |
219 | + progressbar = false; | |
220 | + } | |
221 | + if(args["nooptimization"].is_set()){ | |
222 | + optimization = false; | |
223 | + } | |
224 | + | |
225 | + std::string headername = infile + ".hdr"; //guess the header file name | |
226 | + | |
227 | + size_t optcount = args.nopts(); | |
228 | + | |
229 | + | |
230 | + //open the input ENVI file | |
231 | + if(stim::envi::is_envi(infile)){ //if the input file is an ENVI file, open it | |
232 | + ENVI.open(infile, infile + ".hdr"); | |
233 | + if(!ENVI){ | |
234 | + std::cout<<"ERROR: failed to open input ENVI file: "<<infile<<std::endl; | |
235 | + return 1; | |
236 | + } | |
237 | + X = ENVI.header.samples; | |
238 | + Y = ENVI.header.lines; | |
239 | + B = ENVI.header.bands; | |
240 | + if(args["memraw"].is_set()) ENVI.set_buffer_raw((size_t)args["memraw"].as_int(0) * 1000000); | |
241 | + else ENVI.set_buffer_frac(args["mempct"].as_float(0) / 100.0); //set the buffer size for processing the ENVI file | |
242 | + } | |
243 | + else { | |
244 | + std::cout << "ERROR: the input file does not appear to be an ENVI hyperspectral file: " << infile << std::endl; | |
245 | + return 1; | |
246 | + } | |
247 | + | |
248 | + //display the input and output files | |
249 | + std::cout<<"input: "<<infile<<std::endl; | |
250 | + std::cout<<"output: "<<outfile<<std::endl; | |
251 | + | |
252 | + time_t t1=time(NULL); //start time | |
253 | + | |
254 | + //open the mask, if set | |
255 | + if(args["mask"].is_set()){ //if a mask file is specified | |
256 | + | |
257 | + if(args["mask"].nargs() == 1) | |
258 | + set_mask(args["mask"].as_string(0)); | |
259 | + else if(args["mask"].nargs() == 2) | |
260 | + set_mask(args["mask"].as_string(0), args["mask"].as_int(1)); | |
261 | + } | |
262 | + | |
263 | + if(args["threshold"].is_set()){ | |
264 | + | |
265 | + double mask_band = args["threshold"].as_float(0); | |
266 | + //double threshold = args["threshold"].as_float(1); | |
267 | + double lower, upper; | |
268 | + lower = args["threshold"].as_float(1); | |
269 | + upper = std::numeric_limits<double>::max(); //set the default maximum value to the maximum possible double value | |
270 | + if(args["threshold"].nargs() == 3){ | |
271 | + upper = args["threshold"].as_float(2); | |
272 | + } | |
273 | + | |
274 | + unsigned long long N = X * Y; | |
275 | + | |
276 | + //get the mask size (samples * lines) | |
277 | + unsigned char* mask = (unsigned char*)malloc(N * sizeof(unsigned char)); //allocate memory for the mask | |
278 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
279 | + std::cout<<"Creating a mask at band "<<mask_band<<" with threshold ["<<lower<<", "<<upper<<"]..."<<std::endl; | |
280 | + ENVI.build_mask(mask, mask_band, lower, upper, MASK, true); //get the mask | |
281 | + t1.join(); | |
282 | + | |
283 | + | |
284 | + stim::image<unsigned char> mask_image(mask, X, Y); | |
285 | + mask_image.save(outfile.c_str()); //save the mask image | |
286 | + | |
287 | + //count the number of pixels that are masked | |
288 | + unsigned long long P = 0; | |
289 | + for(unsigned long long i = 0; i < N; i++) | |
290 | + if(mask[i] != 0) P++; | |
291 | + | |
292 | + std::cout<<P<<" out of "<<N<<" pixels masked ("<<(double)P/N * 100<<"%)"<<std::endl; | |
293 | + } | |
294 | + else if( args["mask-finite"].is_set() ){ | |
295 | + unsigned long long N = X * Y; | |
296 | + | |
297 | + std::cout<<"Creating a mask for finite values..."<<std::endl; | |
298 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
299 | + unsigned char* mask = (unsigned char*)malloc(N * sizeof(unsigned char)); | |
300 | + ENVI.mask_finite(mask, MASK, true); | |
301 | + t1.join(); | |
302 | + | |
303 | + stim::image<unsigned char> mask_image(mask, X, Y); | |
304 | + mask_image.save(outfile.c_str()); //save the mask image | |
305 | + | |
306 | + //count the number of pixels that are masked | |
307 | + unsigned long long P = 0; | |
308 | + for(unsigned long long i = 0; i < N; i++) | |
309 | + if(mask[i] != 0) P++; | |
310 | + | |
311 | + std::cout<<N-P<<" pixels have been marked as not finite ("<<(double)(N-P)/(double)N * 100<<"%)"<<std::endl; | |
312 | + //std::cout<<P<<" out of "<<N<<" pixels masked ("<<(double)P/N * 100<<"%)"<<std::endl; | |
313 | + } | |
314 | + | |
315 | + //if baseline input is provided | |
316 | + else if(args["baseline"].is_set()){ | |
317 | + | |
318 | + //if only a single argument is provided, assume it is a baseline file | |
319 | + if(args["baseline"].nargs() == 1){ | |
320 | + std::vector<double> blpts; //create a vector for the baseline points | |
321 | + | |
322 | + std::ifstream blpt_file; //open the file containing the baseline points | |
323 | + blpt_file.open(args["baseline"].as_string().c_str()); | |
324 | + | |
325 | + //get each baseline point and push it into the vector | |
326 | + double pt; | |
327 | + while(blpt_file>>pt){ | |
328 | + blpts.push_back(pt); | |
329 | + } | |
330 | + | |
331 | + baseline(infile, outfile, headername, blpts, MASK); | |
332 | + | |
333 | + | |
334 | + } | |
335 | + //otherwise assume the points are provided individually | |
336 | + else{ | |
337 | + | |
338 | + std::vector<double> blpts; //create a vector for the baseline points | |
339 | + | |
340 | + size_t npts = args["baseline"].nargs(); //get the number of baseline points | |
341 | + for(unsigned p = 0; p < npts; p++){ //insert each point into the baseline point vector | |
342 | + blpts.push_back(args["baseline"].as_float(p)); | |
343 | + } | |
344 | + | |
345 | + baseline(infile, outfile, headername, blpts, MASK); | |
346 | + } | |
347 | + | |
348 | + } | |
349 | + | |
350 | + else if(args["normalize"].is_set()){ | |
351 | + | |
352 | + //if two parameters are provided for normalization, the second is a mask value | |
353 | + // in that case, normalize to a temporary file and then apply a mask | |
354 | + | |
355 | + if(args["normalize"].nargs() == 0){ | |
356 | + std::cout<<"Calculating vector norm..."<<std::endl; | |
357 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
358 | + ENVI.normalize(outfile, MASK, true); //perform normalization | |
359 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
360 | + } | |
361 | + else{ | |
362 | + double normband = args["normalize"].as_float(0); | |
363 | + std::cout<<"Normalizing to band "<<normband<<"..."<<std::endl; | |
364 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
365 | + ENVI.ratio(outfile, normband, MASK, true); //perform normalization | |
366 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
367 | + } | |
368 | + | |
369 | + } | |
370 | + else if (args["select"]) { //if the user specifies the --select option (use bands to create a new file) | |
371 | + size_t nb = args["select"].nargs(); //get the number of bands that the user wants to select | |
372 | + std::vector<double> bandlist(nb); //allocate an array to store the bands selected from the input file | |
373 | + for (size_t b = 0; b < nb; b++) //for each band given by the user | |
374 | + bandlist[b] = args["select"].as_float(b); //store that band in the bandlist array | |
375 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
376 | + ENVI.select(outfile, bandlist, MASK, true); //call an ENVI function to | |
377 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
378 | + | |
379 | + } | |
380 | + | |
381 | + else if(args["apply-mask"].is_set()){//can mostly copy/paste this code | |
382 | + | |
383 | + MASK = (unsigned char*) malloc(X * Y * sizeof(unsigned char)); //allocate space for the mask | |
384 | + memset(MASK, 255, X*Y*sizeof(unsigned char)); | |
385 | + for(size_t m = 0; m < args["apply-mask"].nargs(); m++){ | |
386 | + std::string maskfile = args["apply-mask"].as_string(m); //mask file name | |
387 | + stim::image<unsigned char> mask_image(maskfile); | |
388 | + for(size_t xy = 0; xy < X*Y; xy++) | |
389 | + if(!mask_image.data()[xy]) MASK[xy] = 0; | |
390 | + } | |
391 | + | |
392 | + //run the function to apply the mask | |
393 | + // this outputs a new binary file called 'outfile' with the mask applied | |
394 | + std::cout<<"Applying mask(s) to image..."<<std::endl; | |
395 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
396 | + ENVI.apply_mask(outfile, MASK, true); | |
397 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
398 | + } | |
399 | + | |
400 | + else if (args["sift"].is_set()){ | |
401 | + | |
402 | + //get the name of the mask file (an image file) as a string | |
403 | + std::string maskname = args["sift"].as_string(); | |
404 | + | |
405 | + stim::image<unsigned char> mask(maskname); | |
406 | + | |
407 | + //run the function to apply the mask and save sifted spectra | |
408 | + // this outputs a new binary file called 'outfile' (and associated header) with the mask applied. | |
409 | + | |
410 | + std::cout<<"Sifting to a [ P x B ] = [ "<<mask.nnz()<<" x "<<B<<"] matrix..."<<std::endl; | |
411 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
412 | + ENVI.sift(outfile, mask.data(), true); | |
413 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
414 | + | |
415 | + } | |
416 | + | |
417 | + else if (args["unsift"].is_set()){ | |
418 | + | |
419 | + //get the name of the mask file (an image file) as a string | |
420 | + std::string maskname = args["unsift"].as_string(); | |
421 | + | |
422 | + //load the mask | |
423 | + stim::image<unsigned char> mask(maskname); | |
424 | + | |
425 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
426 | + | |
427 | + //unsift the mask, creating the image outfile | |
428 | + ENVI.unsift(outfile, mask.data(), mask.width(), mask.height(), true); | |
429 | + | |
430 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
431 | + | |
432 | + | |
433 | + } | |
434 | + | |
435 | + else if(args["convert"].is_set()){ | |
436 | + | |
437 | + //get the orientation of the destination file | |
438 | + std::string interleave_name = args["convert"].as_string(); | |
439 | + stim::envi_header::interleaveType interleave_type; | |
440 | + if(interleave_name == "bip") | |
441 | + interleave_type = stim::envi_header::BIP; | |
442 | + else if(interleave_name == "bil") | |
443 | + interleave_type = stim::envi_header::BIL; | |
444 | + else if(interleave_name == "bsq") | |
445 | + interleave_type = stim::envi_header::BSQ; | |
446 | + else{ | |
447 | + std::cout<<"ERROR - unrecognized interleave format: "<<interleave_name<<std::endl; | |
448 | + exit(1); | |
449 | + } | |
450 | + | |
451 | + | |
452 | + //convert(infile, outfile, headername, interleave_type); | |
453 | + std::cout<<"Converting..."<<std::endl; | |
454 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
455 | + ENVI.convert(outfile, interleave_type, progressbar, verbose, optimization); //perform the conversion | |
456 | + ENVI.close(); | |
457 | + t1.detach(); //wait for the progress bar thread to finish (it probably already is) | |
458 | + | |
459 | + } | |
460 | + | |
461 | + //given a text file, output all metrics into a binary file | |
462 | + else if(args["metrics"]){ | |
463 | + std::vector< std::vector<double> > metrics; //create a vector to store metrics | |
464 | + if(args["metrics"].is_num(0)){ //if the first argument of the metrics option is a number, a metric is specified | |
465 | + metrics.resize(1); //create one metric | |
466 | + metrics[0].resize(9, 0); //the allocate space for the entire metric | |
467 | + for(size_t i = 0; i < 9; i++) metrics[0][i] = args["metrics"].as_float(i); //store the metric in the vector | |
468 | + } | |
469 | + else{ | |
470 | + std::string metric_file = args["metrics"].as_string(0); | |
471 | + metrics = read_metric_list(metric_file); | |
472 | + std::cout<<"Computing "<<metrics.size()<<" metrics..."<<std::endl; | |
473 | + } | |
474 | + create_metric_file(metrics, outfile); | |
475 | + } | |
476 | + | |
477 | + //output an image | |
478 | + else if(args["image"].is_set()){ | |
479 | + | |
480 | + if (args["image"].nargs() == 0){ | |
481 | + std::cout << "ERROR: no image parameters specified" << std::endl; | |
482 | + exit(1); | |
483 | + } | |
484 | + double band = args["image"].as_float(0); | |
485 | + stim::colormapType cmap = str2cmap(args["colormap"].as_string(0)); | |
486 | + | |
487 | + if(args["image"].nargs() < 3) | |
488 | + bandimage(infile, headername, band, outfile, cmap, MASK); | |
489 | + else{ | |
490 | + double minVal = args["image"].as_float(1); | |
491 | + double maxVal = args["image"].as_float(2); | |
492 | + bandimage(infile, headername, band, outfile, minVal, maxVal, cmap, MASK); | |
493 | + } | |
494 | + | |
495 | + } | |
496 | + | |
497 | + //Output a single spectrum to a CSV file | |
498 | + else if(args["spectrum"].is_set()){ | |
499 | + | |
500 | + if (args["spectrum"].nargs() != 2){ | |
501 | + std::cout << "ERROR: spectrum requires 2 parameters" << std::endl; | |
502 | + exit(1); | |
503 | + } | |
504 | + unsigned int x = args["spectrum"].as_int(0); //get the x and y positions of the desired spectrum | |
505 | + unsigned int y = args["spectrum"].as_int(1); | |
506 | + | |
507 | + float* spectrum = (float*)malloc(ENVI.header.bands * sizeof(float)); //allocate space to store the spectrum | |
508 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
509 | + ENVI.spectrum(spectrum, x, y, true); //get the spectrum | |
510 | + t1.join(); //end the progress bar thread | |
511 | + | |
512 | + //output the average spectrum | |
513 | + std::ofstream csv(outfile.c_str()); //open a CSV file to write the mean | |
514 | + | |
515 | + /*if (ENVI.header.wavelength.size() > 0) //output the first wavelength | |
516 | + csv << ENVI.header.wavelength[0]<<','; | |
517 | + csv << spectrum[0]; //output the first variable | |
518 | + for (unsigned long long b = 1; b < B; b++) //for each band | |
519 | + csv << "," << spectrum[b]; //output the next variable | |
520 | + */ | |
521 | + for (unsigned long long b = 0; b < B; b++) { //for each band | |
522 | + if (ENVI.header.wavelength.size() == B) //output the wavelength, if available | |
523 | + csv << ENVI.header.wavelength[b] << ','; | |
524 | + else | |
525 | + csv << b << ","; | |
526 | + csv << spectrum[b] << std::endl; //output the next variable | |
527 | + } | |
528 | + csv.close(); //close the file | |
529 | + | |
530 | + | |
531 | + } | |
532 | + //calculate the average spectrum and save to a CSV file | |
533 | + else if(args["mean"].is_set()){ | |
534 | + | |
535 | + unsigned long long XY = X * Y; //number of pixels in the image | |
536 | + | |
537 | + double* m = (double*)malloc(sizeof(double) * B); //allocate space to store the mean spectrum | |
538 | + double* std = (double*) malloc(sizeof(double) * B); //allocate space to store the standard deviation | |
539 | + | |
540 | + std::cout<<"Calculating mean spectrum..."<<std::endl; | |
541 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
542 | + ENVI.mean_spectrum(m, std, MASK, true); //calculate average spectrum | |
543 | + t1.join(); //end the progress bar thread | |
544 | + | |
545 | + //output the spectrum | |
546 | + std::ofstream csv(outfile.c_str()); //open a CSV file to write the mean | |
547 | + for (unsigned long long b = 1; b < B; b++) { //for each band | |
548 | + if (ENVI.header.wavelength.size() == B) //output the wavelength, if available | |
549 | + csv << ENVI.header.wavelength[b] << ','; | |
550 | + else | |
551 | + csv << b << ","; //otherwise output a band number | |
552 | + csv << m[b] << "," << std[b] << std::endl; | |
553 | + } | |
554 | + | |
555 | + | |
556 | + | |
557 | + | |
558 | + | |
559 | + //output the average spectrum | |
560 | + /*std::ofstream csv(outfile.c_str()); //open a CSV file to write the mean | |
561 | + csv<<m[0]; //output the first variable | |
562 | + for(unsigned long long b = 1; b < B; b++) //for each band | |
563 | + csv<<","<<m[b]; //output the next variable | |
564 | + | |
565 | + //output the standard deviation | |
566 | + csv<<std::endl; | |
567 | + csv<<std[0]; | |
568 | + for(unsigned long long b = 1; b < B; b++) //for each band | |
569 | + csv<<","<<std[b]; //output the next variable | |
570 | + */ | |
571 | + csv.close(); //close the output file | |
572 | + | |
573 | + free(m); //free memory storing the mean spectrum | |
574 | + free(std); | |
575 | + } | |
576 | + | |
577 | + //calculate the median spectrum and save to a CSV file | |
578 | + else if(args["median"].is_set()){ | |
579 | + double* m = (double*)malloc(B * sizeof(double)); //allocate space for the median spectrum | |
580 | + | |
581 | + std::cout<<"Calculating mean spectrum..."<<std::endl; | |
582 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
583 | + ENVI.median_spectrum(m, MASK, true); //calculate average spectrum | |
584 | + t1.join(); //end the progress bar thread | |
585 | + | |
586 | + //output the median spectrum | |
587 | + std::ofstream csv(outfile.c_str()); //open a CSV file to write the mean | |
588 | + csv<<m[0]; //output the first variable | |
589 | + for(unsigned long long b = 1; b < B; b++) //for each band | |
590 | + csv<<","<<m[b]; //output the next variable | |
591 | + free(m); | |
592 | + } | |
593 | + | |
594 | + //calculate the covariance matrix | |
595 | + else if(args["covariance"].is_set()){ | |
596 | + if(ENVI.header.interleave == stim::envi_header::BSQ){ | |
597 | + std::cout<<"ERROR: covariance matrix calculation is not implemented for BSQ files"<<std::endl; | |
598 | + exit(1); | |
599 | + } | |
600 | + //calculate the mean | |
601 | + unsigned long long XY = X * Y; //number of pixels in the image | |
602 | + | |
603 | + double* mu = (double*)malloc(sizeof(double) * B); | |
604 | + double* std = (double*)malloc(sizeof(double) * B); | |
605 | + | |
606 | + std::thread t1; //create a thread to manage the progress bar | |
607 | + if(args["covariance"].nargs() == 1){ //if a mean spectrum is given | |
608 | + std::cout<<"Loading mean spectrum from "<<args["covariance"].as_string(0)<<"..."<<std::endl; | |
609 | + stim::table mu_table; //create a CSV table | |
610 | + mu_table.read_ascii(args["covariance"].as_string(0)); //read the table | |
611 | + std::vector< std::vector<double> > mu_vector = mu_table.get_vector<double>(); //get the table contents as an STL vector | |
612 | + for(size_t b = 0; b < B; b++){ | |
613 | + mu[b] = mu_vector[0][b]; | |
614 | + } | |
615 | + } | |
616 | + else{ | |
617 | + t1 = std::thread(progress_thread_envi, &ENVI); //start the progress bar thread | |
618 | + std::cout<<"Calculating mean spectrum..."<<std::endl; | |
619 | + ENVI.mean_spectrum(mu, std, MASK, true); //calculate average spectrum | |
620 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
621 | + } | |
622 | + | |
623 | + double *co = (double*)malloc(sizeof(double)* B * B); //allocate space for the covariance matrix | |
624 | + | |
625 | + std::cout<<"Calculating covariance matrix..."<<std::endl; | |
626 | + t1 = std::thread(progress_thread_envi, &ENVI); //start the progress bar thread | |
627 | + int cuda_device = args["cuda"].as_int(); | |
628 | + ENVI.co_matrix(co, mu, MASK, cuda_device, true); //calculate covariance matrix | |
629 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
630 | + | |
631 | + //output the covariance matrix | |
632 | + std::ofstream csv(outfile.c_str()); //open a CSV file to write the mean | |
633 | + for(unsigned long long b0 = 0; b0 < B; b0++){ | |
634 | + csv<<co[b0 * B]; | |
635 | + for(unsigned long long b1 = 1; b1 < B; b1++) //for each band | |
636 | + csv<<","<<co[b0 * B + b1]; //output the next variable | |
637 | + csv<<std::endl; | |
638 | + } | |
639 | + | |
640 | + csv.close(); //close the output file | |
641 | + free(mu); //free memory for the mean spectrum | |
642 | + free(co); //free memory for the covariance matrix | |
643 | + } | |
644 | + | |
645 | + else if(args["convolve"].is_set()){ | |
646 | + std::vector<double> coef(args["convolve"].nargs()); //allocate an array of values to store the coefficients | |
647 | + for(size_t c = 0; c < coef.size(); c++){ //for each coefficient | |
648 | + std::string s = args["convolve"].as_string(c); | |
649 | + if(s.find('/') != std::string::npos){ | |
650 | + size_t slash = s.find('/'); | |
651 | + double a = atof(s.substr(0, slash).c_str()); | |
652 | + double b = atof(s.substr(slash+1, s.length() - slash+1).c_str()); | |
653 | + std::cout<<s.substr(slash+1, s.length() - slash+1)<<"-----"<<std::endl; | |
654 | + coef[c] = a/b; | |
655 | + } | |
656 | + else coef[c] = args["convolve"].as_float(c); //get the floating point value from the parser | |
657 | + std::cout<<coef[c]<<std::endl; | |
658 | + } | |
659 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
660 | + ENVI.convolve(outfile, coef, 0, ENVI.header.bands - coef.size(), 0, MASK, true); | |
661 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
662 | + } | |
663 | + | |
664 | + else if(args["sg"].is_set()){ | |
665 | + int N = 5; | |
666 | + if(args["sg"].nargs() > 0) | |
667 | + N = args["sg"].as_int(0); | |
668 | + int D = 3; | |
669 | + if(args["sg"].nargs() > 1) | |
670 | + D = args["sg"].as_int(1); | |
671 | + | |
672 | + if(N % 2 == 0 || N <= 0){ | |
673 | + std::cout<<"ERROR: number of points in a Savitzky-Golay filter must be odd and positive"<<std::endl; | |
674 | + exit(1); | |
675 | + } | |
676 | + if(D <= 0){ | |
677 | + std::cout<<"ERROR: the order of a Savitzky-Golay filter must be positive"<<std::endl; | |
678 | + exit(1); | |
679 | + } | |
680 | + if(N < D){ | |
681 | + std::cout<<"ERROR: the number of points for a Savitzky-Golay filter must be greater than the order"<<std::endl; | |
682 | + exit(1); | |
683 | + } | |
684 | + | |
685 | + | |
686 | + | |
687 | + | |
688 | + // calculate the coefficients using the method described in: | |
689 | + // https://en.wikipedia.org/wiki/Savitzky%E2%80%93Golay_filter#Derivation_of_convolution_coefficients | |
690 | + // C = (J^T * J)^(-1) * Jt | |
691 | + stim::matrix<double> J(N, D+1); //create the J matrix | |
692 | + int r = -N / 2; | |
693 | + for(int n = 0; n < N; n++){ | |
694 | + for(int d = 0; d < D + 1; d++){ | |
695 | + J(n, d) = pow(n + r, d); | |
696 | + } | |
697 | + } | |
698 | + | |
699 | + stim::matrix<double> Jt = J.transpose(); //calculate the matrix transpose Jt | |
700 | + | |
701 | + | |
702 | + stim::matrix<double> JtJ = Jt * J; //multiply the transpose by J | |
703 | + | |
704 | + stim::matrix<double> JtJi = JtJ; //allocate space for the matrix inverse | |
705 | + int* piv = (int*) malloc(JtJi.rows() * sizeof(int)); //allocate space to store the LU decomposition pivot indices | |
706 | + LAPACKE_dgetrf(LAPACK_COL_MAJOR, (int)JtJi.rows(), (int)JtJi.cols(), JtJi.data(), (int)JtJi.rows(), piv); //use LAPACK for LU decomposition | |
707 | + LAPACKE_dgetri(LAPACK_COL_MAJOR, (int)JtJi.rows(), JtJi.data(), (int)JtJi.rows(), piv); //use LAPACK to solve the inverse | |
708 | + | |
709 | + | |
710 | + stim::matrix<double> C = JtJi * Jt; //calculate C | |
711 | + | |
712 | + std::vector<double> coef(N); //initialize the coefficient list | |
713 | + for(int c = 0; c < N; c++) | |
714 | + coef[c] = C(0, c); | |
715 | + | |
716 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
717 | + ENVI.convolve(outfile, coef, 0, ENVI.header.bands - coef.size(), coef.size()/2, MASK, true); | |
718 | + t1.join(); | |
719 | + | |
720 | + } | |
721 | + | |
722 | + else if(args["deriv"].is_set()){ | |
723 | + size_t d = 1; | |
724 | + if(args["deriv"].nargs() > 0) | |
725 | + d = args["deriv"].as_int(0); | |
726 | + size_t order = 2; | |
727 | + if(args["deriv"].nargs() > 1) | |
728 | + order = args["deriv"].as_int(1); | |
729 | + | |
730 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
731 | + ENVI.deriv(outfile, d, order, MASK, true); | |
732 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
733 | + } | |
734 | + | |
735 | + //do PCA and save PCs into a file | |
736 | + else if (args["pca"].is_set()){ | |
737 | + | |
738 | + if(ENVI.header.interleave != stim::envi_header::BIP){ | |
739 | + std::cout<<"Error: Calculating PCA using BSQ or BIL files is impractical. Convert to a BIP format using --convert bip."<<std::endl; | |
740 | + exit(1); | |
741 | + } | |
742 | + | |
743 | + unsigned long long XY = ENVI.header.lines * ENVI.header.samples; | |
744 | + unsigned long long B = ENVI.header.bands; | |
745 | + | |
746 | + //calculate correlation matrix | |
747 | + double * mu = (double*)malloc(sizeof(double) * B); | |
748 | + double * std = (double*)malloc(sizeof(double) * B); | |
749 | + double *co = (double*)malloc(sizeof(double)* B * B); | |
750 | + std::cout<<"Averaging..."<<std::endl; | |
751 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
752 | + ENVI.mean_spectrum(mu, std, MASK, true); //calculate average spectrum | |
753 | + | |
754 | + for(size_t b = 0; b < B; b++){ //for each band, test for non-finite values, exit if found | |
755 | +#ifdef _WIN32 | |
756 | + if(!_finite(mu[b])){ //if the value at index i is not finite | |
757 | +#else | |
758 | + if(!std::isfinite(mu[b])){ //C++11 implementation | |
759 | +#endif | |
760 | + std::cout<<"error calculating PCA: the data set contains non-finite values in band "<<b<<". Use --mask-finite to create a mask of finite values."<<std::endl; | |
761 | + exit(1); | |
762 | + } | |
763 | + } | |
764 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
765 | + | |
766 | + | |
767 | + std::cout<<"Calculating the covariance matrix..."<<std::endl; | |
768 | + t1 =std::thread(progress_thread_envi, &ENVI); //start the progress bar thread | |
769 | + int cuda_device = args["cuda"].as_int(); | |
770 | + ENVI.co_matrix(co, mu, MASK, cuda_device, true); //calculate correlation coefficient | |
771 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
772 | + | |
773 | + | |
774 | + //calculate eigen values and eigen vectors | |
775 | + //cv::Mat correlation((int)B, (int)B, CV_64FC1, co); | |
776 | + //cv::Mat eigenvalues((int)B, 1, CV_64FC1); | |
777 | + //cv::Mat eigenvectors((int)B, (int)B, CV_64FC1); | |
778 | + std::cout<<"Calculating eigenvectors (LAPACK)..."<<std::endl; | |
779 | + //cv::eigen(correlation, eigenvalues, eigenvectors); //calculate eigen values and eigen vectors | |
780 | + | |
781 | + double* lambda_real = (double*) malloc(B * sizeof(double)); | |
782 | + double* lambda_imag = (double*) malloc(B * sizeof(double)); | |
783 | + double* evec = (double*) malloc(B * B * sizeof(double)); | |
784 | + LAPACKE_dgeev(LAPACK_COL_MAJOR, 'N', 'V', (int)B, co, (int)B, lambda_real, lambda_imag, NULL, (int)B, evec, (int)B); | |
785 | + std::ofstream csv(outfile.c_str(), std::ios::out); //create a text file to store the PCA stats (mean and covariance matrix) | |
786 | + | |
787 | + csv<<mu[0]; //output the mean spectrum | |
788 | + for(unsigned long long i = 1; i < B; i++) | |
789 | + csv<<","<<mu[i]; | |
790 | + csv<<std::endl; | |
791 | + | |
792 | + /*for (unsigned long long j = 0; j < B; j++){ //output the principle components | |
793 | + csv<<eigenvectors.at<double>((int)j, 0); | |
794 | + for (unsigned long long i = 1; i < B; i++) | |
795 | + csv<<","<<eigenvectors.at<double>((int)j, (int)i); | |
796 | + csv << std::endl; | |
797 | + }*/ | |
798 | + for(size_t j = 0; j < B; j++){ | |
799 | + csv<<evec[j * B + 0]; //output the first element of the eigenvector | |
800 | + for(size_t i = 1; i < B; i++){ | |
801 | + csv<<","<<evec[j * B + i]; //output all consecutive elements | |
802 | + } | |
803 | + csv<<std::endl; | |
804 | + } | |
805 | + csv.close(); //close the text file | |
806 | + | |
807 | + free(mu); | |
808 | + free(co); | |
809 | + } | |
810 | + | |
811 | + else if (args["project"].is_set()){ | |
812 | + std::string pcfile = args["project"].as_string(0); | |
813 | + | |
814 | + //recommend user to convert file to BIP file before do rotation | |
815 | + if (ENVI.header.interleave == stim::envi_header::BSQ || ENVI.header.interleave == stim::envi_header::BIL){ | |
816 | + std::cout << "ERROR: Rotation is only practical for a BIP image; convert the image to BIP" << std::endl; | |
817 | + exit(1); | |
818 | + } | |
819 | + unsigned long long XY = ENVI.header.lines * ENVI.header.samples; //calculate the size of the image | |
820 | + unsigned long long B = ENVI.header.bands; //calculate the number of bands | |
821 | + unsigned long long N = B; //set the default number of PCs to the maximum | |
822 | + if(args["project"].nargs() > 1) //if the number of PCs is specified | |
823 | + N = args["project"].as_int(1); //retrieve the specified number of PCs | |
824 | + | |
825 | + std::ifstream csv(pcfile.c_str(), std::ios::in); //open the statistics file | |
826 | + if(!csv){ std::cout<<"ERROR reading statistics file: "<<pcfile<<std::endl; exit(1); } //make sure the stats file is valid | |
827 | + double* basis = (double*)malloc(sizeof(double) * B * N); //allocate space for the basis matrix | |
828 | + | |
829 | + double *mu = (double*)malloc(sizeof(double) * B); //allocate space for the mean feature vector | |
830 | + | |
831 | + std::cout<<"Loading basis statistics..."<<std::endl; | |
832 | + | |
833 | + std::string line, token; | |
834 | + std::getline(csv, line); | |
835 | + std::stringstream ss(line); | |
836 | + for(unsigned i = 0; i < B; i++){ //load the mean feature vector | |
837 | + std::getline(ss, token, ','); | |
838 | + mu[i] = atof(token.c_str()); | |
839 | + } | |
840 | + | |
841 | + for (unsigned long long n = 0; n < N; n++){ //for each component | |
842 | + std::getline(csv, line); | |
843 | + //std::cout<<N<<" "<<B<<" "<<prog<<std::endl; | |
844 | + | |
845 | + std::stringstream ss1(line); | |
846 | + //ss = std::stringstream(line); | |
847 | + for (unsigned long long b = 0; b < B; b++){ //for each feature | |
848 | + std::getline(ss1, token, ','); | |
849 | + basis[n * B + b] = atof(token.c_str()); | |
850 | + //prog = (double)((n+1) * B + b+1) / (double)(B * N) * 100; | |
851 | + //std::cout<<b<<", "<<n<<", "<<B<<", "<<N<<", "<<prog<<std::endl; | |
852 | + } | |
853 | + //exit(1); | |
854 | + } | |
855 | + //t1.join(); | |
856 | + | |
857 | + std::cout<<"Projecting onto the new basis..."<<std::endl; | |
858 | + //double prog = 0; | |
859 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
860 | + std::vector<double> pcs(N); | |
861 | + if (N == B) pcs = ENVI.header.wavelength; | |
862 | + else { | |
863 | + for (size_t n = 0; n < N; n++) | |
864 | + pcs[n] = (double)(n + 1); | |
865 | + } | |
866 | + int cuda_device = args["cuda"].as_int(); | |
867 | + ENVI.project(outfile, mu, basis, N, pcs, MASK, cuda_device, true); | |
868 | + t1.join(); | |
869 | + } | |
870 | + | |
871 | + else if (args["inverse"].is_set()){ | |
872 | + std::string pcfile = args["inverse"].as_string(0); | |
873 | + | |
874 | + //recommend user to convert file to BIP file before do rotation | |
875 | + if (ENVI.header.interleave == stim::envi_header::BSQ || ENVI.header.interleave == stim::envi_header::BIL){ | |
876 | + std::cout << "ERROR: Rotation is only practical for a BIP image; convert the image to BIP" << std::endl; | |
877 | + exit(1); | |
878 | + } | |
879 | + unsigned long long XY = ENVI.header.lines * ENVI.header.samples; //calculate the size of the image | |
880 | + unsigned long long M = ENVI.header.bands; //calculate the number of bands | |
881 | + unsigned long long C = M; //set the default number of coefficients to the maximum | |
882 | + if(args["inverse"].nargs() > 1) //if the number of coefficients to be used is specified | |
883 | + C = args["inverse"].as_int(1); //retrieve the specified number of coefficients | |
884 | + | |
885 | + std::ifstream csv(pcfile.c_str(), std::ios::in); //open the statistics file | |
886 | + std::string line, token; | |
887 | + std::getline(csv, line); | |
888 | + unsigned long long B = 1; //count the number of spectral components that will be produced | |
889 | + for(unsigned long long c = 0; c < line.size(); c++){ //for each character in the first line | |
890 | + if(line[c] == ',') B++; //count the number of commas | |
891 | + } | |
892 | + | |
893 | + double* basis = (double*)malloc(sizeof(double) * B * C); //allocate space for the basis matrix | |
894 | + double *mu = (double*)malloc(sizeof(double) * B); //allocate space for the mean feature vector | |
895 | + | |
896 | + std::stringstream ss(line); | |
897 | + for(unsigned long long i = 0; i < B; i++){ //load the mean feature vector | |
898 | + std::getline(ss, token, ','); | |
899 | + mu[i] = atof(token.c_str()); | |
900 | + } | |
901 | + | |
902 | + for (unsigned long long n = 0; n < C; n++){ //for each component | |
903 | + std::getline(csv, line); | |
904 | + //ss = std::stringstream(line); | |
905 | + | |
906 | + std::stringstream ss1(line); | |
907 | + for (unsigned long long b = 0; b < B; b++){ //for each feature | |
908 | + std::getline(ss1, token, ','); | |
909 | + basis[n * B + b] = atof(token.c_str()); | |
910 | + } | |
911 | + } | |
912 | + | |
913 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
914 | + ENVI.inverse(outfile, mu, basis, B, C, true); | |
915 | + t1.join(); | |
916 | + } | |
917 | + | |
918 | + else if (args["crop"].is_set()){ | |
919 | + //initialize the values to the maximum extents | |
920 | + unsigned long long x = 0; | |
921 | + unsigned long long y = 0; | |
922 | + unsigned long long b = 0; | |
923 | + unsigned long long nx = X; | |
924 | + unsigned long long ny = Y; | |
925 | + unsigned long long nb = B; | |
926 | + | |
927 | + // Define the default behavior for the parameters | |
928 | + // (I'm trying to be intuitive) | |
929 | + | |
930 | + if(args["crop"].as_string(0)[0] != '-'){ | |
931 | + x = args["crop"].as_int(0); | |
932 | + nx = X - x; | |
933 | + } | |
934 | + if(args["crop"].nargs() > 1 && args["crop"].as_string(1)[0] != '-') | |
935 | + nx = args["crop"].as_int(1); | |
936 | + | |
937 | + if(args["crop"].nargs() > 2 && args["crop"].as_string(2)[0] != '-'){ | |
938 | + y = args["crop"].as_int(2); | |
939 | + ny = Y - y; | |
940 | + } | |
941 | + if(args["crop"].nargs() > 3 && args["crop"].as_string(3)[0] != '-') | |
942 | + ny = args["crop"].as_int(3); | |
943 | + | |
944 | + if(args["crop"].nargs() > 4 && args["crop"].as_string(4)[0] != '-'){ | |
945 | + if (ENVI.header.wavelength.size()) { //if wavelength values are specified in the file | |
946 | + double wavelength = args["crop"].as_float(4); //assume that the coordinates are given in wavelength | |
947 | + size_t low, high; | |
948 | + ENVI.band_bounds(wavelength, low, high); | |
949 | + b = low; | |
950 | + } | |
951 | + else { //if wavelength values aren't given, assume the user parameter is in bands | |
952 | + b = args["crop"].as_int(4); | |
953 | + } | |
954 | + nb = B - b; | |
955 | + } | |
956 | + if (args["crop"].nargs() > 5 && args["crop"].as_string(5)[0] != '-') { | |
957 | + if (ENVI.header.wavelength.size()) { //if wavelength values are specified in the file | |
958 | + double nw = args["crop"].as_float(5); //assume that the coordinates are given in wavelength | |
959 | + double wavelength = args["crop"].as_float(4) + nw; | |
960 | + size_t low, high; | |
961 | + ENVI.band_bounds(wavelength, low, high); | |
962 | + nb = high - b; | |
963 | + } | |
964 | + else { //if wavelength values aren't given, assume the user parameter is in bands | |
965 | + b = args["crop"].as_int(5); | |
966 | + } | |
967 | + } | |
968 | + | |
969 | + if(x + nx > X || y + ny > Y || b + nb > B){ | |
970 | + std::cout<<"ERROR: specified image is out of bounds."<<std::endl; | |
971 | + exit(1); | |
972 | + } | |
973 | + std::cout<<"Cropping image to [ "<<nx<<" x "<<ny<<" x "<<nb<<" ]..."<<std::endl; | |
974 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
975 | + ENVI.crop(outfile, x, y, x + nx - 1, y + ny - 1, b, b + nb - 1, true); //call the ENVI cropping function | |
976 | + | |
977 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
978 | + } | |
979 | + //generate a set of subimages from a mask file | |
980 | + else if(args["subimages"].is_set()){ | |
981 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
982 | + | |
983 | + set_mask(args["subimages"].as_string(0)); | |
984 | + | |
985 | + size_t nx = 11; | |
986 | + if(args["subimages"].nargs() >= 2) | |
987 | + nx = args["subimages"].as_int(1); //get the width of the subimages | |
988 | + size_t ny = nx; //assume that the subimages are square | |
989 | + if(args["subimages"].nargs() >= 3) //if the image height is specified | |
990 | + ny = args["subimages"].as_int(2); //set the height | |
991 | + | |
992 | + ENVI.subimages(outfile, nx, ny, MASK, true); | |
993 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
994 | + } | |
995 | + else if(args["trim"].is_set()){ | |
996 | + std::vector<size_t> bands; //create a list of band indices to trim | |
997 | + std::vector<size_t> idx; | |
998 | + //std::vector< std::pair<double, double> > trim_ranges; //create an array of pairs | |
999 | + double w0, w1; //create a pair of wavelength values | |
1000 | + size_t i; | |
1001 | + for(size_t p = 0; p < args["trim"].nargs(); p++){ | |
1002 | + std::string s = args["trim"].as_string(p); //get the first value as a string | |
1003 | + i = s.find('-'); //get the index of the dash (if it exists) | |
1004 | + if(i != std::string::npos && i != 0){ //if the string contains a dash (-) and that dash isn't the first value (negative number) | |
1005 | + s[i] = ' '; //replace the dash with a space | |
1006 | + std::stringstream ss(s); //create a string stream | |
1007 | + ss>>w0; //store the first and second values as a range | |
1008 | + ss>>w1; | |
1009 | + idx = ENVI.header.band_indices(w0, w1); //get the band indices in this range | |
1010 | + bands.insert(bands.end(), idx.begin(), idx.end()); //insert them into the band array | |
1011 | + } | |
1012 | + else{ //otherwise | |
1013 | + w0 = args["trim"].as_float(p); //otherwise store the single wavelength | |
1014 | + idx = ENVI.header.band_index(w0); //get the band(s) associated with that wavelength | |
1015 | + if(idx.size() == 1) //if only one band exists | |
1016 | + bands.push_back(idx[0]); //add it to the band array (if there are two indices, there isn't a single band associated with the wavelength) | |
1017 | + } | |
1018 | + } | |
1019 | + std::cout<<"Trimming "<<bands.size()<<" / "<<ENVI.header.bands<<" bands"<<std::endl; | |
1020 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
1021 | + ENVI.trim(outfile, bands, true); //trim the bands and store the result | |
1022 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
1023 | + } | |
1024 | + else if(args["combine"].is_set()){ | |
1025 | + std::string otherfile(args["combine"].as_string(0)); //get the name for the file to combine with this one | |
1026 | + stim::envi C; | |
1027 | + C.open(otherfile, otherfile + ".hdr"); //open the file to combine | |
1028 | + | |
1029 | + long long px = 0; //get the position of the second image | |
1030 | + long long py = 0; | |
1031 | + if(args["combine"].nargs() == 1){ //if no arguments are given, the files are concatenated along Y | |
1032 | + px = 0; | |
1033 | + py = ENVI.header.lines; | |
1034 | + } | |
1035 | + if(args["combine"].nargs() > 1){ //if one argument is provided, assume it is X | |
1036 | + px = args["combine"].as_int(1); | |
1037 | + if(px < (long long)ENVI.header.samples) py = ENVI.header.samples; //if no Y is given, and x is less than the maximum X, concatenate along Y | |
1038 | + } | |
1039 | + if(args["combine"].nargs() > 2) | |
1040 | + py = args["combine"].as_int(2); | |
1041 | + if( (-px < (long long)C.header.samples) && | |
1042 | + ( px < (long long)ENVI.header.samples) && | |
1043 | + (-py < (long long)C.header.lines) && | |
1044 | + ( py < (long long)ENVI.header.lines)){ | |
1045 | + std::cout<<"ERROR: The files to be combined are overlapping. The extent for the input image is: ["<<ENVI.header.samples<<", "<<ENVI.header.lines<<"]"; | |
1046 | + exit(1); | |
1047 | + } | |
1048 | + std::cout<<"Combining images..."<<std::endl; | |
1049 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
1050 | + ENVI.combine(outfile, C, px, py, true); | |
1051 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
1052 | + } | |
1053 | + else if (args["append"]) { //append a file to the input in the band dimension | |
1054 | + std::string otherfile(args["append"].as_string(0)); //get the name of the file to append to this one | |
1055 | + stim::envi C; //create an ENVI file object | |
1056 | + C.open(otherfile, otherfile + ".hdr"); //open the appending file | |
1057 | + | |
1058 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
1059 | + ENVI.append(outfile, C, true); //append the files and write the output | |
1060 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
1061 | + C.close(); //close the appended file | |
1062 | + } | |
1063 | + /*else if(args["mosaic"].is_set()){ | |
1064 | + if (args["mosaic"].as_string() == "cary"){ | |
1065 | + //use the file extension to determine if the mosaic is an interferogram or spectrum | |
1066 | + stim::filename f(infile); | |
1067 | + if(f.extension() == "drd" || f.extension() == "DRD") | |
1068 | + mosaic_agilent_interferogram(infile, outfile, args["elwn"].as_float(0), args["udr"].as_int(0)); | |
1069 | + | |
1070 | + } | |
1071 | + if(args["mosaic"].as_string(0) == "spero"){ | |
1072 | + mosaic_spero(infile, outfile); | |
1073 | + } | |
1074 | + else { | |
1075 | + std::cout << "ERROR: mosaic construction has been moved to other executables." << std::endl; | |
1076 | + exit(1); | |
1077 | + } | |
1078 | + }*/ | |
1079 | + /*else if(args["fft"].is_set()){ //if the user requests batch FFT processing | |
1080 | + | |
1081 | + double wn_min = args["fft-range"].as_float(0); //get the minimum and maximum bounds for the spectrum | |
1082 | + double wn_max = args["fft-range"].as_float(1); | |
1083 | + double elwn = args["elwn"].as_float(0); //get the Effective Laser Wave Number | |
1084 | + int udr = args["udr"].as_int(0); //get the UDR filter/sampling method | |
1085 | + | |
1086 | + bool ratio = false; //default to calculating a ratio | |
1087 | + void* background = NULL; | |
1088 | + stim::agilent_binary<float> bkg; | |
1089 | + if(args["background"].is_set()){ //if a background is specified | |
1090 | + stim::filename bkg_file(args["background"].as_string(0)); //create a filename for the background file | |
1091 | + if(bkg_file.extension() != "seq"){ | |
1092 | + std::cout<<"ERROR - Agilent SEQ file expected for the background."<<std::endl; | |
1093 | + exit(1); | |
1094 | + } | |
1095 | + std::cout<<"background file: "<<args["background"].as_string(0)<<std::endl; | |
1096 | + bkg.load(args["background"].as_string(0)); //load the background interferogram | |
1097 | + ratio = true; | |
1098 | + } | |
1099 | + if(ENVI){ //if the input file is an ENVI mosaic | |
1100 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
1101 | + | |
1102 | + if(ratio){ | |
1103 | + background = (void*) malloc(bkg.bytes()); //allocate a pointer for the raw background data | |
1104 | + bkg.bip((float*)background); //copy the background interferogram to a BIP file | |
1105 | + } | |
1106 | + size_t samples = 0; | |
1107 | + if(args["fft"].nargs() == 1) samples = args["fft"].as_int(0); | |
1108 | + ENVI.fft(outfile, wn_min, wn_max, samples, background, bkg.dim(0), bkg.dim(1), true, args["cuda"].as_int()); //if the input is an ENVI file, run the ENVI FFT | |
1109 | + | |
1110 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
1111 | + }*/ | |
1112 | + /*else{ | |
1113 | + stim::filepath fp = infile; | |
1114 | + stim::filename f(fp, "*.drd"); | |
1115 | + std::vector<stim::filename> drd_list = f.get_list(); //generate a list of DRD files | |
1116 | + if(drd_list.size() == 0){ | |
1117 | + std::cerr<<"ERROR: no interferogram (*.drd) files found."<<std::endl; | |
1118 | + exit(1); | |
1119 | + } | |
1120 | + | |
1121 | + double progress = 0; | |
1122 | + std::thread t1(progress_thread_double, &progress); //start the progress bar thread | |
1123 | + for(size_t i = 0; i < drd_list.size(); i++){ | |
1124 | + //std::cout<<drd_list[i].str()<<std::endl; | |
1125 | + stim::agilent_binary<float> interferogram(drd_list[i].str()); //load the interferogram | |
1126 | + interferogram.meancenter(); //mean center the interferogram | |
1127 | + interferogram.zeropad(); //pad to the nearest power-of-two | |
1128 | + stim::agilent_binary<float> fft = interferogram.fft(wn_min, wn_max, elwn, udr); //calculate the FFT and crop out the desired wavenumber range | |
1129 | + if(i == 0){ //if this is the first file | |
1130 | + stim::envi_header header = fft.create_header(); //create a header | |
1131 | + header.save(drd_list[0].extension("hdr")); //save the header | |
1132 | + } | |
1133 | + | |
1134 | + if(ratio) fft.absorbance(&bkg_fft); //if we are calculating a ratio to a background, calculate the absorbance | |
1135 | + fft.save(drd_list[i].extension("dmd")); //save the output file as a DMD | |
1136 | + //std::cout<<progress<<std::endl; | |
1137 | + progress = (double)(i+1) / (double) drd_list.size() * 100; | |
1138 | + } | |
1139 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
1140 | + } | |
1141 | + }*/ | |
1142 | + else if(args["mnf"].is_set()){ | |
1143 | + if (args["mnf"].nargs() == 0){ | |
1144 | + std::cout << "ERROR: no mnf parameters specified" << std::endl; | |
1145 | + exit(1); | |
1146 | + } | |
1147 | + int keptComponents = args["mnf"].as_int(0); //get the user-specified number of components to keep | |
1148 | + std::string component_file; | |
1149 | + if(args["mnf"].nargs() == 2) | |
1150 | + component_file = args["mnf"].as_string(1); | |
1151 | + int device = args["cuda"].as_int(); | |
1152 | + mnf(outfile, keptComponents, component_file, device); | |
1153 | + } | |
1154 | + | |
1155 | + else if(args["multiply"].is_set()){ | |
1156 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
1157 | + double val = args["multiply"].as_float(0); //get the value to multiply by | |
1158 | + ENVI.multiply(outfile, val, MASK, true); //multiply by val | |
1159 | + t1.join(); //wait for the progress bar thread to finish | |
1160 | + } | |
1161 | + else if(args["add"].is_set()){ | |
1162 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
1163 | + double val = args["add"].as_float(0); //get the value to multiply by | |
1164 | + ENVI.add(outfile, val, MASK, true); //multiply by val | |
1165 | + t1.join(); //wait for the progress bar thread to finish | |
1166 | + } | |
1167 | + else{ | |
1168 | + std::cout<<"ERROR: no algorithm is specified"<<std::endl; | |
1169 | + exit(1); | |
1170 | + } | |
1171 | + | |
1172 | + time_t t2=time(NULL); //end time | |
1173 | + size_t processing_time = t2 - t1; | |
1174 | + std::cout<<" processing time : "<<processing_time<<" s"<<std::endl<<std::endl<<std::endl; | |
1175 | + std::cout<<" data rate: "<<(double)ENVI.bytes() / 1000000 / processing_time<<" MB/s"<<std::endl; | |
1176 | + | |
1177 | + //close the input file | |
1178 | + ENVI.close(); | |
1179 | +} | ... | ... |
1 | +++ a/src/proc/metric.cpp | |
1 | +#include <iostream> | |
2 | +#include <fstream> | |
3 | +#include <time.h> | |
4 | +#include <thread> | |
5 | +#include <iterator> | |
6 | +#include "stim/envi/envi_header.h" | |
7 | +#include "stim/envi/bip.h" | |
8 | +#include "stim/envi/bil.h" | |
9 | +#include "stim/envi/bsq.h" | |
10 | +#include "stim/envi/envi.h" | |
11 | +#include "stim/envi/binary.h" | |
12 | + | |
13 | +void progress_thread_double(double* e); | |
14 | + | |
15 | +extern stim::envi ENVI; | |
16 | +extern unsigned char* MASK; | |
17 | + | |
18 | +/// Reads a file of numbers separated by lines and white space into a 2D STL array | |
19 | +std::vector<std::string> tokenize(std::string str){ | |
20 | + // construct a stream from the string | |
21 | + std::stringstream strstr(str); | |
22 | + | |
23 | + // use stream iterators to copy the stream to the vector as whitespace separated strings | |
24 | + std::istream_iterator<std::string> it(strstr); | |
25 | + std::istream_iterator<std::string> end; | |
26 | + std::vector<std::string> results(it, end); | |
27 | + | |
28 | + // send the vector to stdout. | |
29 | + //std::ostream_iterator<std::string> oit(std::cout); | |
30 | + //std::copy(results.begin(), results.end(), oit); | |
31 | + return results; | |
32 | +} | |
33 | + | |
34 | +/// Convert a metric file into an array of metric parameters | |
35 | +std::vector< std::vector<double> > read_metric_list(std::string filename){ | |
36 | + std::ifstream infile(filename); | |
37 | + if(!infile){ | |
38 | + std::cout<<"ERROR opening metric file: "<<filename<<std::endl; | |
39 | + exit(1); | |
40 | + } | |
41 | + std::vector< std::vector<double> > metrics; | |
42 | + std::string line; //stores the metric parameters as a series of values in text | |
43 | + while(std::getline(infile, line)){ //for each line in the input file | |
44 | + std::vector<std::string> tokens = tokenize(line); //break the line into tokens | |
45 | + std::vector<double> metric_params; //create an array to store the metric parameters | |
46 | + for(size_t t = 0; t < tokens.size(); t++){ //for each token | |
47 | + metric_params.push_back(atof(tokens[t].c_str())); | |
48 | + } | |
49 | + metrics.push_back(metric_params); | |
50 | + } | |
51 | + return metrics; //return the list of metrics and parameters | |
52 | + | |
53 | +} | |
54 | + | |
55 | +/// Creates an ENVI file filled with the given metrics, based on the Bhargava format | |
56 | +void create_metric_file(std::vector< std::vector<double> > metrics, std::string outfile){ | |
57 | + | |
58 | + //warn if the data set is BIP or BIL | |
59 | + if (ENVI.header.interleave == stim::envi_header::BIL || | |
60 | + ENVI.header.interleave == stim::envi_header::BIP) { | |
61 | + std::cout << "WARNING: metric processing is slow for BIL and BIP files - recommend changing to BSQ" << std::endl; | |
62 | + } | |
63 | + | |
64 | + double progress = 0; | |
65 | + std::thread t1(progress_thread_double, &progress); //start the progress bar thread | |
66 | + std::ofstream target(outfile.c_str(), std::ios::binary); //create an output file for writing the metrics | |
67 | + | |
68 | + size_t XYbytes = ENVI.header.samples * ENVI.header.lines * ENVI.header.valsize(); //size of a band in bytes | |
69 | + void* M = malloc(XYbytes); //allocate space to store the metric result | |
70 | + | |
71 | + stim::envi_header new_header = ENVI.header; //copy the current header | |
72 | + | |
73 | + new_header.bands = metrics.size(); //set the number of bands to the number of metrics | |
74 | + new_header.interleave = stim::envi_header::BSQ; //the metric output file will be BSQ | |
75 | + new_header.band_names.resize(metrics.size()); //re-set the band names (names will be filled in below) | |
76 | + new_header.wavelength.clear(); //clear the wavelengths - the output won't have wavelengths | |
77 | + bool success = false; | |
78 | + for(size_t m = 0; m < metrics.size(); m++){ //for each metric | |
79 | + std::stringstream name_str; | |
80 | + switch( (unsigned)metrics[m][0] ){ | |
81 | + case 1: //peak height ratio | |
82 | + if (ENVI.ph_to_ph(M, | |
83 | + metrics[m][1], | |
84 | + metrics[m][2], | |
85 | + metrics[m][3], | |
86 | + metrics[m][4], | |
87 | + metrics[m][5], | |
88 | + metrics[m][6], | |
89 | + MASK)){ | |
90 | + success = true; | |
91 | + name_str << metrics[m][3] << " : " << metrics[m][6] << "\n"; | |
92 | + new_header.band_names[m] = name_str.str(); | |
93 | + } | |
94 | + else success = false; | |
95 | + break; | |
96 | + case 2: //peak area to height ratio | |
97 | + if (ENVI.pa_to_ph(M, | |
98 | + metrics[m][1], | |
99 | + metrics[m][2], | |
100 | + metrics[m][3], | |
101 | + metrics[m][4], | |
102 | + metrics[m][5], | |
103 | + metrics[m][6], | |
104 | + metrics[m][7], | |
105 | + MASK)) { | |
106 | + success = true; | |
107 | + name_str << metrics[m][3] << " : [" << metrics[m][6] << ", " << metrics[m][7] << "]\n"; | |
108 | + new_header.band_names[m] = name_str.str(); | |
109 | + } | |
110 | + else success = false; | |
111 | + break; | |
112 | + case 3: //peak area to area ratio | |
113 | + if (ENVI.pa_to_pa(M, | |
114 | + metrics[m][1], | |
115 | + metrics[m][2], | |
116 | + metrics[m][3], | |
117 | + metrics[m][4], | |
118 | + metrics[m][5], | |
119 | + metrics[m][6], | |
120 | + metrics[m][7], | |
121 | + metrics[m][8], | |
122 | + MASK)) { | |
123 | + success = true; | |
124 | + name_str << "[" << metrics[m][3] << ", " << metrics[m][4] << "] : [" << metrics[m][6] << ", " << metrics[m][7] << "]\n"; | |
125 | + new_header.band_names[m] = name_str.str(); | |
126 | + } | |
127 | + else success = false; | |
128 | + break; | |
129 | + case 4: //center of gravity | |
130 | + if (ENVI.centroid(M, | |
131 | + metrics[m][1], | |
132 | + metrics[m][2], | |
133 | + metrics[m][3], | |
134 | + metrics[m][4], | |
135 | + MASK)) { | |
136 | + success = true; | |
137 | + name_str << "[" << metrics[m][3] << ", " << metrics[m][4] << "]\n"; | |
138 | + new_header.band_names[m] = name_str.str(); | |
139 | + } | |
140 | + else success = false; | |
141 | + break; | |
142 | + default: | |
143 | + std::cout << "ERROR loading metric " << m << " from metric file" << std::endl; | |
144 | + exit(1); | |
145 | + } | |
146 | + if (!success) { | |
147 | + progress = 100; | |
148 | + t1.join(); | |
149 | + progress = ((double)(m + 1) / (double)metrics.size()) * 100; //save the progress | |
150 | + std::cout << std::endl << "ERROR processing metric " << m + 1 << ":" << std::endl; | |
151 | + std::cout << metrics[m][0] << " " | |
152 | + << metrics[m][1] << " " | |
153 | + << metrics[m][2] << " " | |
154 | + << metrics[m][3] << " " | |
155 | + << metrics[m][4] << " " | |
156 | + << metrics[m][5] << " " | |
157 | + << metrics[m][6] << " " | |
158 | + << metrics[m][6] << " " | |
159 | + << metrics[m][6] << std::endl; | |
160 | + exit(1); | |
161 | + } | |
162 | + target.write((const char*)M, XYbytes); //write the metric results to a file | |
163 | + progress = ( (double)(m+1) / (double)metrics.size() ) * 100; //save the progress | |
164 | + } | |
165 | + t1.join(); //end the progress bar thread | |
166 | + | |
167 | + new_header.save(outfile + ".hdr"); | |
168 | + | |
169 | +} | ... | ... |
1 | +++ a/src/proc/mnf.cpp | |
1 | +#include <iostream> | |
2 | +#include <stim/envi/envi.h> | |
3 | +#include "stim/envi/envi_header.h" | |
4 | +#include "stim/parser/arguments.h" | |
5 | +#include <stim/image/image.h> | |
6 | +#include <stim/math/matrix.h> | |
7 | +#include <time.h> | |
8 | +//#include <opencv2/opencv.hpp> | |
9 | +#include <fstream> | |
10 | +#include <thread> | |
11 | +#include "stim/envi/bil.h" | |
12 | +//#include <opencv2/core/core.hpp> | |
13 | + | |
14 | +//LAPACKE support for Visual Studio | |
15 | +#include <complex> | |
16 | +#ifndef LAPACK_COMPLEX_CUSTOM | |
17 | +#define LAPACK_COMPLEX_CUSTOM | |
18 | +#define lapack_complex_float std::complex<float> | |
19 | +#define lapack_complex_double std::complex<double> | |
20 | +#endif | |
21 | +#include "lapacke.h" | |
22 | + | |
23 | + | |
24 | + | |
25 | + | |
26 | +void progress_thread_envi(stim::envi* e); //progress bar threaded function | |
27 | + | |
28 | + | |
29 | +extern unsigned char* MASK; //pointer to an input file mask if one is provided | |
30 | +extern stim::envi ENVI; //input ENVI file to be processed | |
31 | +extern unsigned long long X, Y, B; //registers to quickly access the image size | |
32 | + | |
33 | + | |
34 | + | |
35 | + ///comparison function to compare two values corresponding to two memory addresses a and b | |
36 | + ///is used in qsort function to sort elements of an array (ex.eigenvalues) and getting the corresponding indices. | |
37 | +int cmpfunc(const void * a, const void * b) | |
38 | +{ | |
39 | + | |
40 | + double *x = *(double **)a; double *y = *(double **)b; | |
41 | + | |
42 | + return *x > *y ? 1 : -1; | |
43 | + | |
44 | +} | |
45 | + | |
46 | + | |
47 | +/// multiply matrix A (nxm) by matrix B (mxp) | |
48 | +/// @param MatA is a pointer to the matrix A | |
49 | +/// @param MatB is a pointer to the matrix B | |
50 | +/// @param MatC is a pointer to pre-allocated memory of size [n * p * sizeof(double)] that stores the result of multiplication. | |
51 | +/// @param rowsX and @param columnsX are integers refering to the number of rows and columns of the matrix X respectively. | |
52 | +/// Note that columnA = rowsB | |
53 | +void multiply_2matrices(const double* MatA, int rowsA, int columnsA, const double* MatB, int rowsB, int columnsB, double* MatC, int rowsC, int columnsC) { | |
54 | + for (int i = 0; i < rowsA; i++) { | |
55 | + for (int j = 0; j < columnsB; j++) { | |
56 | + double sum = 0.0; | |
57 | + for (int k = 0; k < rowsB; k++) | |
58 | + sum = sum + MatA[i * columnsA + k] * MatB[k * columnsB + j]; | |
59 | + MatC[i * columnsC + j] = sum; //resulting matrix C is [nxp] | |
60 | + } | |
61 | + } | |
62 | +} | |
63 | + | |
64 | + | |
65 | + | |
66 | +void mnf(std::string outfile, int keptComponents, std::string NoiseFractions, int cuda_device){ | |
67 | + ///throw an Error in case of invalid values for the number of keptComponents | |
68 | + if (keptComponents <= 0 || keptComponents > B) { | |
69 | + std::cout << "ERROR: keptComponents must be in the range [0 " <<B<<"] (number of bands)"<< std::endl; | |
70 | + exit(1); | |
71 | + } | |
72 | + //throw an error if the ENVI file isn't BIP | |
73 | + if (ENVI.header.interleave != stim::envi_header::BIP) { | |
74 | + std::cout << "ERROR: MNF basis calculation requires a BIP file to make covariance calculation practical" << std::endl; | |
75 | + exit(1); | |
76 | + } | |
77 | + | |
78 | + unsigned long long XY = X * Y; //number of pixels in the image | |
79 | + double* mu = (double*)malloc(sizeof(double) * B); //allocate space for the mean | |
80 | + | |
81 | + std::thread t1(progress_thread_envi, &ENVI); //start the progress bar thread | |
82 | + std::cout << "Calculating mean spectrum..." << std::endl; | |
83 | + ENVI.mean_spectrum(mu, NULL, MASK, true); //calculate average spectrum | |
84 | + | |
85 | + for (size_t b = 0; b < B; b++) { //for each band, test for non-finite values | |
86 | + if (!std::isfinite(mu[b])) //C++11 implementation | |
87 | + std::cout << "WARNING: the mean spectrum contains non-finite values in band " << b << ". Use --mask-finite to create a mask of finite values." << std::endl; | |
88 | + } | |
89 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
90 | + | |
91 | + stim::matrix<double> cov(B, B); //allocate a double-precision covariance matrix | |
92 | + t1 = std::thread(progress_thread_envi, &ENVI); //start the progress bar thread | |
93 | + ENVI.co_matrix(cov.data(), mu, MASK, cuda_device, true); //calculate covariance matrix | |
94 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
95 | + | |
96 | + stim::matrix<double> ncov(B, B); //allocate a double-precision noise covariance matrix | |
97 | + t1 = std::thread(progress_thread_envi, &ENVI); //start the progress bar thread | |
98 | + ENVI.coNoise_matrix(ncov.data(), mu, MASK, cuda_device, true); //calculate covariance of noise matrix | |
99 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
100 | + | |
101 | + | |
102 | + std::cout << std::endl << "Calculating the inverse covariance matrix S^(-1)..."; | |
103 | + int *IPIV = (int*)malloc(sizeof(int) * B); | |
104 | + LAPACKE_dgetrf(LAPACK_COL_MAJOR, (int)B, (int)B, cov.data(), (int)B, IPIV); //perform LU factorization | |
105 | + LAPACKE_dgetri(LAPACK_COL_MAJOR, (int)B, cov.data(), (int)B, IPIV); //calculate matrix inverse | |
106 | + free(IPIV); | |
107 | + std::cout << "done." << std::endl; | |
108 | + | |
109 | + std::cout << std::endl << "Calculating Q = S_n * S^(-1)..."; //calculate the Q matrix | |
110 | + stim::matrix<double> Q = ncov * cov; | |
111 | + std::cout << "done." << std::endl; | |
112 | + | |
113 | + free(mu); //free memory for the mean spectrum | |
114 | + | |
115 | + ///computing the eigenvalues and left eigenvectors of matrix Qmat. | |
116 | + double *EigenvaluesReal = (double*)malloc(B * sizeof(double)); //allocate space for the real part of eigenvalues | |
117 | + double *EigenvaluesIm = (double*)malloc(B * sizeof(double)); //allocate space for the imaginary part of eigenvalues | |
118 | + | |
119 | + std::cout << std::endl << "Calculating left eigenvectors X * A = v * X..."; | |
120 | + stim::matrix<double> ev_left(B, B); | |
121 | + LAPACKE_dgeev(LAPACK_COL_MAJOR, 'V', 'N', (int)B, Q.data(), (int)B, EigenvaluesReal, EigenvaluesIm, ev_left.data(), (int)B, 0, (int)B); //perform eigenvalue decomposition | |
122 | + std::cout << "done." << std::endl; | |
123 | + | |
124 | + std::cout << std::endl << "Sorting eigenvectors..."; | |
125 | + ///SORTING EIGENVECTORS CORRESPONDING TO THEIR EIGENVALUES | |
126 | + //EigenvaluesReal is the original array and "pointers" is the array of corresponding pointers, whose size is the size of the original array. | |
127 | + //Let cmp be the comparison function for qsort(). | |
128 | + double **pointers = (double**)malloc(B * sizeof(double*)); | |
129 | + for (int i = 0; i < B; i++) { | |
130 | + pointers[i] = &EigenvaluesReal[i]; // assign the address of integer. | |
131 | + } | |
132 | + | |
133 | + ///SORTING EIGENVALUES AND GETTING THE INDICES | |
134 | + qsort(pointers, B, sizeof(pointers[0]), cmpfunc); | |
135 | + size_t *EigenSortedIndices = (size_t*)malloc(B * sizeof(size_t)); //allocate space for the Indices of sorted eigenvalues | |
136 | + for (size_t i = 0; i < B; ++i) | |
137 | + EigenSortedIndices[i] = pointers[i] - EigenvaluesReal; //Calculate indices of the sorted eigenvalues | |
138 | + | |
139 | + stim::matrix<double> As = ev_left.sort_cols(EigenSortedIndices); | |
140 | + stim::matrix<double> Ast = As.transpose(); | |
141 | + std::cout << "done." << std::endl; | |
142 | + | |
143 | + free(EigenvaluesReal); | |
144 | + free(EigenvaluesIm); | |
145 | + free(EigenSortedIndices); | |
146 | + | |
147 | + std::cout << std::endl << "Removing noise components..."; | |
148 | + ///Noise removal and then backward transformation (builing one general/final basis matrix to be multiplied wih the raw data) | |
149 | + //General Transformation/Final Basis Matrix = gtm = (inv(As).') * (Keye) * (Ast) ; | |
150 | + //Note that the forward transform is done using transpose of mnf basis (Ast).However, for inverse transform, we use transpose of mnf basis inversed. | |
151 | + | |
152 | + //creating a BxB matrix with the number of 'keptComponents' 1 on the diagonal and 0 elsewhere. | |
153 | + stim::matrix<double> K = stim::matrix<double>::I(B); //create an identity matrix | |
154 | + for (size_t i = keptComponents; i < B; i++) K(i, i) = 0.0; //assign zeros to components that will not be used | |
155 | + | |
156 | + stim::matrix<double> K_Ast = K * Ast; | |
157 | + | |
158 | + //calculate inverse of As matrix | |
159 | + int *IPIV2 = (int*)malloc(sizeof(int) * B); | |
160 | + LAPACKE_dgetrf(LAPACK_COL_MAJOR, (int)B, (int)B, As.data(), (int)B, IPIV2); | |
161 | + LAPACKE_dgetri(LAPACK_COL_MAJOR, (int)B, As.data(), (int)B, IPIV2); | |
162 | + free(IPIV2); | |
163 | + | |
164 | + //calculate transpose of As inversed matrix (transpose of transformation matrix inveresed ) . | |
165 | + stim::matrix<double> Asit = As.transpose(); | |
166 | + | |
167 | + //multiplying As (inversed transposed matrix) by KeyeAst : (inv(As)).' * (KeyeAst) . | |
168 | + stim::matrix<double> G = Asit * K_Ast; | |
169 | + stim::matrix<double> G_t = G.transpose(); | |
170 | + std::cout << "done." << std::endl; | |
171 | + | |
172 | + std::ofstream basisfile(outfile); | |
173 | + basisfile << 0; | |
174 | + for (size_t i = 1; i < B; i++) basisfile << ", " << 0; | |
175 | + basisfile << std::endl; | |
176 | + basisfile << G.csv(); | |
177 | + basisfile.close(); | |
178 | + | |
179 | + //output noise fractions | |
180 | + if (NoiseFractions.size() > 0) { //if a file name is specified for the noise fractions, save them | |
181 | + std::cout << std::endl << "Outputing noise fractions in a CSV file (infile-NoiseFractions)..." << std::endl; | |
182 | + //outputing the sorted Eigenvalues in a CSV file (Noise Fractions) | |
183 | + std::ofstream csv(NoiseFractions.c_str()); //open a CSV file to write the sorted Eigenvalues | |
184 | + csv << EigenSortedIndices[0] << ", " << EigenvaluesReal[EigenSortedIndices[0]]; //output the first variable | |
185 | + for (unsigned long long b = 1; b < B; b++) | |
186 | + csv << "\n" << EigenSortedIndices[b] << ", " << EigenvaluesReal[EigenSortedIndices[b]]; //output the next variable | |
187 | + csv.close(); | |
188 | + } | |
189 | +} //end MNF | ... | ... |
1 | +++ a/src/proc/mosaic.cpp | |
1 | +#include "stim/parser/filename.h" | |
2 | +#include "stim/envi/envi.h" | |
3 | +#include "stim/visualization/colormap.h" | |
4 | +#include "stim/envi/agilent_binary.h" | |
5 | + | |
6 | +#include <thread> | |
7 | +void progress_thread_double(double* e); //progress bar threaded function | |
8 | + | |
9 | + | |
10 | + | |
11 | +void mosaic_coord(unsigned int &x, unsigned int &y, stim::filename dmd_filename){ | |
12 | + | |
13 | + //get the file prefix | |
14 | + std::string prefix = dmd_filename.get_prefix(); | |
15 | + | |
16 | + //these files are in the format: | |
17 | + // ???????????_xxxxx_yyyyy.dmd | |
18 | + | |
19 | + //first find the x coordinate | |
20 | + | |
21 | + //find the position of the last underscore | |
22 | + size_t y_start = prefix.find_last_of("_"); | |
23 | + //remove all values between x_start and the end of the string | |
24 | + std::string y_string = prefix.substr(y_start + 1); | |
25 | + | |
26 | + y = atoi(y_string.c_str()); | |
27 | + | |
28 | + //crop out the x coordinate and the last underscore | |
29 | + prefix = prefix.substr(0, y_start); | |
30 | + | |
31 | + //find the y coordinate using the same method as above | |
32 | + size_t x_start = prefix.find_last_of("_"); | |
33 | + std::string x_string = prefix.substr(x_start + 1); | |
34 | + x = atoi(x_string.c_str()); | |
35 | +} | |
36 | + | |
37 | +//Use the file list to find the number of tiles along each dimension of the mosaic | |
38 | +void mosaic_size(unsigned int &sx, unsigned int &sy, std::vector<stim::filename> dmd_list){ | |
39 | + sx = sy = 0; | |
40 | + | |
41 | + unsigned int xi, yi; | |
42 | + | |
43 | + //for each dmd file | |
44 | + for(unsigned int i = 0; i < dmd_list.size(); i++){ | |
45 | + | |
46 | + //find the coordinate of the tile represented by this file | |
47 | + mosaic_coord(xi, yi, dmd_list[i]); | |
48 | + | |
49 | + //if the coordinate is larger than the current max, store it as the current max | |
50 | + if(xi > sx) sx = xi; | |
51 | + if(yi > sy) sy = yi; | |
52 | + } | |
53 | + | |
54 | + //add 1 to reflect that the indexing starts at 0 | |
55 | + sx++; sy++; | |
56 | +} | |
57 | + | |
58 | +void mosaic_agilent(std::string filemask, std::string outfile, size_t &X, size_t &Y, size_t &B){ | |
59 | + | |
60 | + double progress = 0; | |
61 | + std::thread t1(progress_thread_double, &progress); //start the progress bar thread | |
62 | + | |
63 | + //generate a list of tile files | |
64 | + stim::filename f = filemask; //create a filename from the specified file mask | |
65 | + if(!f.wildcards()) //if the file name doesn't contain wildcards | |
66 | + f = filemask + "/*.dmd"; //default to files of type DMD (generally used as agilent mosaic tiles) } | |
67 | + | |
68 | + std::vector<stim::filename> tile_list = f.get_list(); //create a list of tile files | |
69 | + | |
70 | + stim::agilent_binary<float> binfile(tile_list[0]); //load the first agilent binary file | |
71 | + size_t detector_size = binfile.dim(0); //get the detector size | |
72 | + | |
73 | + std::cout<<"Building a mosaic with a detector size of "<<detector_size<<std::endl; | |
74 | + | |
75 | + //calculate the mosaic size | |
76 | + unsigned int mx, my; | |
77 | + mosaic_size(mx, my, tile_list); | |
78 | + | |
79 | + std::cout<<"Mosaic size: "<<mx<<" "<<my<<std::endl; | |
80 | + | |
81 | + //if(create_header){ //if a header has to be created | |
82 | + std::ifstream in(tile_list[0].str().c_str(), std::ifstream::ate | std::ifstream::binary); //open the first dmd | |
83 | + size_t file_size = in.tellg(); //get the size of the file | |
84 | + B = (file_size - 1020) / (sizeof(float) * detector_size * detector_size); //estimate the number of bands by dividing by the frame size | |
85 | + //} | |
86 | + //else{ | |
87 | + //f = f.path() + "/*.hdr"; //create a mask for the header file (the name is unknown) | |
88 | + //std::vector<stim::filename> hdr_list = f.get_list(); //allocate space for a list of headers that match this pattern | |
89 | + //if(hdr_list.size() == 0){ //throw an error of a header doesn't exist | |
90 | + // std::cout<<"No ENVI header file found. A header file created with Resolutions Pro (export ENVI) provides useful wavelength information. If one is unavailable, use the --create-header option to estimate these properties and create a minimal header file."<<std::endl; | |
91 | + // exit(1); | |
92 | + //} | |
93 | + //std::cout<<"First header name: "<<hdr_list[0].str()<<std::endl; | |
94 | + //open the representative ENVI header file (this should be the header for the thumbnail produced by Resolutions Pro) | |
95 | + //header.load(hdr_list[0].str()); | |
96 | + //} | |
97 | + | |
98 | + //change the header dimensions to reflect the detector size | |
99 | + // this corresponds to the size of the tile along X and Y | |
100 | + stim::envi_header header; //allocate space for an ENVI header | |
101 | + header.samples = detector_size; | |
102 | + header.lines = detector_size; | |
103 | + header.bands = B; | |
104 | + | |
105 | + header.header_offset = 1020; //Agilent binary files have a 1020 byte header | |
106 | + | |
107 | + //create a list of ENVI file structures | |
108 | + std::vector<stim::envi> envi_list; | |
109 | + envi_list.resize(mx * my); //set the length to the number of tiles | |
110 | + | |
111 | + //open each tile | |
112 | + for(unsigned int m = 0; m < mx * my; m++){ | |
113 | + envi_list[m].open(tile_list[m].str(), header); | |
114 | + envi_list[m].close(); | |
115 | + } | |
116 | + | |
117 | + //calculate the size of a single band of the mosaic | |
118 | + X = mx * detector_size; //number of samples | |
119 | + Y = my * detector_size; //number of lines | |
120 | + size_t type_size = envi_list[0].type_size(); //byte size of the data type | |
121 | + size_t tile_width = detector_size * type_size; //byte size of a tile | |
122 | + size_t band_width = X * type_size; //byte width of the band image | |
123 | + size_t band_size = band_width * Y; //size of the band in bytes | |
124 | + | |
125 | + | |
126 | + //allocate space for a single band of the mosaic | |
127 | + char* band = (char*)malloc(band_size); | |
128 | + | |
129 | + //allocate space for a single tile of the mosaic | |
130 | + char* tile_band = (char*)malloc(detector_size * detector_size * type_size); | |
131 | + | |
132 | + //open a binary file for writing | |
133 | + std::ofstream outstream(outfile.c_str(), std::ios::out|std::ios::binary); | |
134 | + | |
135 | + //***********Combine Tiles into a Band Image********************** | |
136 | + | |
137 | + //for each band | |
138 | + for(size_t b = 0; b < B; b++){ | |
139 | + //unsigned int b = 0; | |
140 | + //for each tile along y | |
141 | + for(size_t yt = 0; yt < my; yt++){ | |
142 | + //for each tile along x | |
143 | + for(size_t xt = 0; xt < mx; xt++){ | |
144 | + | |
145 | + envi_list[xt * my + yt].open(); //open the file for reading (windows has a max # of open files) | |
146 | + envi_list[xt * my + yt].band_index((void*)tile_band, b); //load the tile image | |
147 | + envi_list[xt * my + yt].close(); //close the file | |
148 | + | |
149 | + size_t x_idx = xt * tile_width; //calculate the position of this line along x in the output image | |
150 | + | |
151 | + //for each line along y | |
152 | + for(size_t y = 0; y < detector_size; y++){ | |
153 | + size_t y_idx = ((my-1) - yt) * detector_size + y; //calculate the position of this line along y | |
154 | + | |
155 | + //calculate the position of this line in the output image | |
156 | + size_t dst_i = y_idx * band_width + x_idx; | |
157 | + | |
158 | + size_t src_i = y * tile_width; | |
159 | + | |
160 | + memcpy(band + dst_i, tile_band + src_i, tile_width); | |
161 | + } | |
162 | + | |
163 | + } | |
164 | + | |
165 | + } | |
166 | + outstream.write(band, band_size); | |
167 | + progress = (double)(b + 1) / header.bands * 100; | |
168 | + } | |
169 | + | |
170 | + progress = 100; | |
171 | + | |
172 | + //close the binary file | |
173 | + outstream.close(); | |
174 | + | |
175 | + //free the memory allocated for the tile and output bands | |
176 | + free(tile_band); | |
177 | + free(band); | |
178 | + | |
179 | + //update and save the header | |
180 | + //header.samples = X; | |
181 | + //header.lines = Y; | |
182 | + //header.header_offset = 0; //the final output doesn't have an offset | |
183 | + //header.save(outfile + ".hdr"); | |
184 | + | |
185 | + t1.join(); //wait for the progress bar thread to finish (it probably already is) | |
186 | +} | |
187 | + | |
188 | +void mosaic_agilent_spectrum(){ | |
189 | + | |
190 | +} | |
191 | + | |
192 | +void mosaic_agilent_interferogram(std::string filemask, std::string outfile, double ELWN, int UDR){ | |
193 | + | |
194 | + size_t X, Y, B; //store the size of the mosaic | |
195 | + mosaic_agilent(filemask, outfile, X, Y, B); //generate the mosaic | |
196 | + | |
197 | + //create the header | |
198 | + stim::envi_header header; | |
199 | + header.samples = X; | |
200 | + header.lines = Y; | |
201 | + header.bands = B; | |
202 | + | |
203 | + double int_delta = (1.0 / ELWN) * ((double)UDR / 2.0); //calculate the interferogram spacing | |
204 | + | |
205 | + header.set_wavelengths(0, int_delta); | |
206 | + header.wavelength_units = "centimeters"; | |
207 | + header.save(outfile + ".hdr"); | |
208 | + | |
209 | +} | |
210 | + | |
211 | + | ... | ... |
1 | +++ a/src/proc/spero.cpp | |
1 | +#include "stim/parser/filename.h" | |
2 | +#include "stim/envi/envi.h" | |
3 | +#include "stim/visualization/colormap.h" | |
4 | + | |
5 | +#include <thread> | |
6 | +#include <algorithm> | |
7 | +#include <unordered_map> | |
8 | +#include <fstream> | |
9 | +void progress_thread_double(double* e); //progress bar threaded function | |
10 | + | |
11 | +struct speroFile{ | |
12 | + int x; | |
13 | + int y; | |
14 | + stim::filename headername; | |
15 | +}; | |
16 | + | |
17 | +void spero_coord(int &x, int &y, stim::filename filename){ | |
18 | + | |
19 | + //get the file prefix | |
20 | + std::string prefix = filename.get_prefix(); | |
21 | + | |
22 | + //these files are in the format: | |
23 | + // ???????????[xxxxx_yyyyy][??????????].hdr | |
24 | + | |
25 | + //first find the x coordinate | |
26 | + | |
27 | + //find the position of the first bracket | |
28 | + size_t start = prefix.find_first_of("[") + 1; //find the first element of the y coordinate | |
29 | + prefix = prefix.substr(start, prefix.length() - start); | |
30 | + size_t end = prefix.find_first_of("_"); //find the index of the last element of the y coordinate | |
31 | + | |
32 | + std::string x_string = prefix.substr(0, end); | |
33 | + | |
34 | + x = atoi(x_string.c_str()); | |
35 | + | |
36 | + //crop out the x coordinate and the last underscore | |
37 | + prefix = prefix.substr(end + 1, prefix.length() - end); | |
38 | + end = prefix.find_first_of("]"); | |
39 | + std::string y_string = prefix.substr(0, end); | |
40 | + | |
41 | + y = atoi(y_string.c_str()); | |
42 | + //find the y coordinate using the same method as above | |
43 | +/* size_t x_start = prefix.find_last_of("_"); | |
44 | + std::string x_string = prefix.substr(x_start + 1); | |
45 | + x = atoi(x_string.c_str());*/ | |
46 | +} | |
47 | + | |
48 | +void mosaic_spero(std::string directory, std::string outfile){ | |
49 | + | |
50 | + std::cout<<"Building a mosaic from SPERO frames..."<<std::endl; | |
51 | + | |
52 | + //generate a list of dmd files | |
53 | + stim::filename f = directory + "/*.hdr"; | |
54 | + std::vector<stim::filename> hdr_list = f.get_list(); | |
55 | + | |
56 | + std::vector<speroFile> speroFiles; //create a list of spero files | |
57 | + speroFiles.resize(hdr_list.size()); //pre-allocate to save time (we know how many there are) | |
58 | + for(size_t i = 0; i < hdr_list.size(); i++){ //for each header name | |
59 | + spero_coord(speroFiles[i].x, speroFiles[i].y, hdr_list[i]); | |
60 | + speroFiles[i].headername = hdr_list[i].str(); | |
61 | + //speroFiles[i].file.open(hdr_list[i].str_noext(), hdr_list[i].str()); | |
62 | + //speroFiles[i].file.close(); //close the file (can only keep so many open at once) | |
63 | + } | |
64 | + | |
65 | + //calculate the height of the image by looking at how many files have the same x coordinate | |
66 | + size_t height = 0; //stores the width of the array | |
67 | + int first_x; //the first x value encountered | |
68 | + for(size_t i = 0; i < speroFiles.size(); i++){ //for each file | |
69 | + if(i == 0) first_x = speroFiles[i].x; //if this is the first file, store the x coordinate | |
70 | + else{ //otherwise | |
71 | + if(speroFiles[i].x != first_x){ //if the x-coord of this file is not the same as the first file | |
72 | + height = (int)i; //we now know the number of files | |
73 | + break; //exit the loop | |
74 | + } | |
75 | + } | |
76 | + } | |
77 | + size_t width = speroFiles.size() / height; //the number of files should be divisible by the width to get the height | |
78 | + | |
79 | + | |
80 | + std::vector<int> yvals(height); //stores the height values | |
81 | + for(size_t i = 0; i < height; i++) //go through the first "width" files and store their y values | |
82 | + yvals[i] = speroFiles[i].y; | |
83 | + | |
84 | + std::vector<int> xvals(width); //stores the width values | |
85 | + for(size_t i = 0; i < speroFiles.size(); i += height) //go through every "width" file and store the x coordinate | |
86 | + xvals[i/height] = speroFiles[i].x; | |
87 | + | |
88 | + std::sort(&yvals[0], &yvals[0] + yvals.size()); //sort both arrays of coordinates | |
89 | + std::sort(&xvals[0], &xvals[0] + xvals.size()); | |
90 | + | |
91 | + //create a mapping from the x and y coordinates to their indices | |
92 | + std::unordered_map<int, size_t> x2idx; | |
93 | + std::unordered_map<int, size_t> y2idx; | |
94 | + | |
95 | + for(size_t i = 0; i < height; i++) y2idx.insert(std::pair<int, size_t>(yvals[i], i)); //unordered maps now give an index for a coordinate | |
96 | + for(size_t i = 0; i < width; i++) x2idx.insert(std::pair<int, size_t>(xvals[i], i)); | |
97 | + | |
98 | + std::vector<stim::envi> M; //create an array of ENVI files in mosaic order | |
99 | + M.resize(speroFiles.size()); | |
100 | + | |
101 | + size_t xi, yi; | |
102 | + for(size_t i = 0; i < M.size(); i++){ //for each input file | |
103 | + xi = x2idx[speroFiles[i].x]; //get the x and y indices for this file's position in the mosaic | |
104 | + yi = y2idx[speroFiles[i].y]; | |
105 | + | |
106 | + M[yi * width + xi].open(speroFiles[i].headername.str_noext(), speroFiles[i].headername.str()); //open the ENVI file and set parameters | |
107 | + M[yi * width + xi].close(); //close the file, since we can only open so many | |
108 | + } | |
109 | + | |
110 | + std::ofstream target(outfile.c_str(), std::ios::binary); //create a file to store the output | |
111 | + | |
112 | + stim::envi_header h = M[0].header; //create a header for the mosaic | |
113 | + h.samples *= width; | |
114 | + h.lines *= height; | |
115 | + size_t tile_width = M[0].header.samples; | |
116 | + size_t tile_height = M[0].header.lines; | |
117 | + | |
118 | + //h.bands = 10; | |
119 | + | |
120 | + double progress = 0; | |
121 | + std::thread t1(progress_thread_double, &progress); //start the progress bar thread | |
122 | + | |
123 | + float* band = (float*) malloc(h.samples * h.lines * sizeof(float)); //allocate space for a band image | |
124 | + float* tile_band = (float*) malloc(tile_width * tile_height * sizeof(float)); | |
125 | + size_t dst, src; | |
126 | + for(size_t b = 0; b < h.bands; b++){ | |
127 | + for(size_t yi = 0; yi < height; yi++){ | |
128 | + for(size_t xi = 0; xi < width; xi++){ | |
129 | + M[yi * width + xi].open(); | |
130 | + M[yi * width + xi].band_index(tile_band, b); | |
131 | + for(size_t y = 0; y < tile_height; y++){ | |
132 | + dst = (yi * tile_height + tile_height - y - 1) * h.samples + xi * tile_width; | |
133 | + src = y * tile_width; | |
134 | + memcpy(band + dst, tile_band + src, sizeof(float) * tile_width); | |
135 | + } | |
136 | + //stim::cpu2image(tile_band, outfile + ".bmp", tile_width, tile_height, stim::cmBrewer); | |
137 | + //exit(1); | |
138 | + M[yi * width + xi].close(); | |
139 | + | |
140 | + progress = (double)((b+1) * (yi+1) * (xi + 1)) / (width * height * h.bands) * 100; | |
141 | + } | |
142 | + } | |
143 | + target.write((char*)band, h.samples * h.lines * sizeof(float)); | |
144 | + //stim::cpu2image(band, outfile + ".bmp", h.samples, h.lines, stim::cmBrewer); | |
145 | + //exit(1); | |
146 | + } | |
147 | + | |
148 | + t1.join(); //wait for the thread to terminate | |
149 | + | |
150 | + target.close(); //close the output file | |
151 | + h.save(outfile + ".hdr"); //write the header | |
152 | + | |
153 | + free(band); | |
154 | +} | |
0 | 155 | \ No newline at end of file | ... | ... |
1 | +++ a/src/progress_t.cpp | |
1 | +#include <stim/ui/progressbar.h> | |
2 | +#include <stim/envi/envi.h> | |
3 | + | |
4 | +void progress_thread_envi(stim::envi* e){ | |
5 | + unsigned int p = 0; | |
6 | + unsigned int new_p; | |
7 | + e->reset_progress(); | |
8 | + while(p != 100){ | |
9 | + new_p = (unsigned)e->progress(); | |
10 | + if(new_p > p){ | |
11 | + p = new_p; | |
12 | + rtsProgressBar(p); | |
13 | + std::cout<<" "<<(double)e->data_rate() / 1000<<" kB/s "; | |
14 | + } | |
15 | + } | |
16 | + std::cout<<endl; //put a newline after the completed progress bar | |
17 | +} | |
18 | + | |
19 | +void progress_thread_double(double* e){ | |
20 | + unsigned int p = 0; | |
21 | + *e = 0; | |
22 | + rtsProgressBar(p); | |
23 | + while(p != 100){ | |
24 | + p = (unsigned)(*e); | |
25 | + rtsProgressBar(p); | |
26 | + } | |
27 | + std::cout<<endl; //put a newline after the completed progress bar | |
28 | + | |
29 | +} | ... | ... |
1 | +++ a/src/progress_thread.h | |
1 | +#ifndef PROGRESS_THREAD | |
2 | +#define PROGRESS_THREAD | |
3 | + | |
4 | +//function to display a progress bar | |
5 | +void progressbar_thread(double* e){ | |
6 | + | |
7 | + unsigned int p = 0; | |
8 | + while(p != 100){ | |
9 | + std::cout.flush(); | |
10 | + if(*e > p){ | |
11 | + p = (unsigned int)(*e); | |
12 | + rtsProgressBar(p); | |
13 | + } | |
14 | + } | |
15 | + std::cout<<std::endl; //put a newline after the completed progress bar | |
16 | +} | |
17 | + | |
18 | +#endif | |
0 | 19 | \ No newline at end of file | ... | ... |
1 | +++ a/src/spero/spero.cpp | |
1 | +#include <iostream> | |
2 | +#include <algorithm> | |
3 | +#include <unordered_map> | |
4 | +#include <stim/parser/arguments.h> | |
5 | +#include <stim/envi/agilent_binary.h> | |
6 | +#include <stim/parser/filename.h> | |
7 | +#include <stim/envi/envi.h> | |
8 | + | |
9 | +stim::arglist args; //generate a list of accepted arguments | |
10 | + | |
11 | +#include <thread> | |
12 | +void progress_thread_double(double* e); //progress bar threaded function | |
13 | + | |
14 | +struct speroFile { | |
15 | + int x; | |
16 | + int y; | |
17 | + stim::filename headername; | |
18 | +}; | |
19 | + | |
20 | +void spero_coord(int &x, int &y, stim::filename filename) { | |
21 | + | |
22 | + //get the file prefix | |
23 | + std::string prefix = filename.get_prefix(); | |
24 | + | |
25 | + //these files are in the format: | |
26 | + // ???????????[xxxxx_yyyyy][??????????].hdr | |
27 | + | |
28 | + //first find the x coordinate | |
29 | + | |
30 | + //find the position of the first bracket | |
31 | + size_t start = prefix.find_first_of("[") + 1; //find the first element of the y coordinate | |
32 | + prefix = prefix.substr(start, prefix.length() - start); | |
33 | + size_t end = prefix.find_first_of("_"); //find the index of the last element of the y coordinate | |
34 | + | |
35 | + std::string x_string = prefix.substr(0, end); | |
36 | + | |
37 | + x = atoi(x_string.c_str()); | |
38 | + | |
39 | + //crop out the x coordinate and the last underscore | |
40 | + prefix = prefix.substr(end + 1, prefix.length() - end); | |
41 | + end = prefix.find_first_of("]"); | |
42 | + std::string y_string = prefix.substr(0, end); | |
43 | + | |
44 | + y = atoi(y_string.c_str()); | |
45 | + //find the y coordinate using the same method as above | |
46 | + /* size_t x_start = prefix.find_last_of("_"); | |
47 | + std::string x_string = prefix.substr(x_start + 1); | |
48 | + x = atoi(x_string.c_str());*/ | |
49 | +} | |
50 | + | |
51 | +bool sperosort(speroFile i, speroFile j) { | |
52 | + return i.x < j.x; | |
53 | +} | |
54 | + | |
55 | +//This function test to make sure that the given file names are valid for a SPERO reconstruction | |
56 | +bool verify_filenames(std::vector<stim::filename> files) { | |
57 | + size_t idx = files[0].prefix().find('['); | |
58 | + if (idx == std::string::npos) return false; | |
59 | + for (size_t i = 0; i < files.size() - 1; i++) { | |
60 | + if (files[i].prefix().substr(0, idx) != files[i + 1].prefix().substr(0, idx)) return false; | |
61 | + } | |
62 | + return true; | |
63 | +} | |
64 | + | |
65 | +void mosaic_spero(std::string directory, std::string outfile) { | |
66 | + | |
67 | + //test for wild-cards in the directory | |
68 | + if (directory.find('*') != std::string::npos || directory.find('?') != std::string::npos) { | |
69 | + std::cout << "ERROR: no wild-cards are allowed, just specify the source directory containing SPERO files" << std::endl; | |
70 | + exit(1); | |
71 | + } | |
72 | + | |
73 | + std::cout << "Building a mosaic from SPERO frames..." << std::endl; | |
74 | + | |
75 | + //generate a list of dmd files | |
76 | + stim::filename f = directory + "/*.hdr"; | |
77 | + std::vector<stim::filename> hdr_list = f.get_list(); | |
78 | + if (hdr_list.size() == 0) { | |
79 | + std::cout << "ERROR: no files found for assembly" << std::endl; | |
80 | + exit(1); | |
81 | + } | |
82 | + std::cout << hdr_list.size() << " files found" << std::endl; | |
83 | + | |
84 | + if (!verify_filenames(hdr_list)) { | |
85 | + std::cout << "ERROR: incorrect file prefix found - all files should have the same prefix" << std::endl; | |
86 | + exit(1); | |
87 | + } | |
88 | + | |
89 | + if (hdr_list.size() == 0) { | |
90 | + std::cout << "ERROR: no header files found in directory '" + directory << std::endl; | |
91 | + exit(1); | |
92 | + } | |
93 | + | |
94 | + std::vector<speroFile> speroFiles; //create a list of spero files | |
95 | + speroFiles.resize(hdr_list.size()); //pre-allocate to save time (we know how many there are) | |
96 | + for (size_t i = 0; i < hdr_list.size(); i++) { //for each header name | |
97 | + spero_coord(speroFiles[i].x, speroFiles[i].y, hdr_list[i]); | |
98 | + speroFiles[i].headername = hdr_list[i].str(); | |
99 | + } | |
100 | + | |
101 | + //sort the SPERO files by x coordinate | |
102 | + std::sort(speroFiles.begin(), speroFiles.end(), sperosort); | |
103 | + | |
104 | + //calculate the height of the image by looking at how many files have the same x coordinate | |
105 | + size_t height = 0; //stores the width of the array | |
106 | + int first_x; //the first x value encountered | |
107 | + for (size_t i = 0; i < speroFiles.size(); i++) { //for each file | |
108 | + if (i == 0) first_x = speroFiles[i].x; //if this is the first file, store the x coordinate | |
109 | + if (first_x == speroFiles[i].x) height++; | |
110 | + else break; | |
111 | + } | |
112 | + size_t width; | |
113 | + if (height == 0) width = speroFiles.size(); | |
114 | + else width = speroFiles.size() / height; //the number of files should be divisible by the width to get the height | |
115 | + | |
116 | + if (width * height != speroFiles.size()) { | |
117 | + std::cout << "ERROR: calculated width and height do not match the number of input files: " << width << " x " << height << " = " << width * height << " found, " << speroFiles.size() << " needed" << std::endl; | |
118 | + exit(1); | |
119 | + } | |
120 | + | |
121 | + std::vector<int> yvals(height); //stores the height values | |
122 | + for (size_t i = 0; i < height; i++) //go through the first "width" files and store their y values | |
123 | + yvals[i] = speroFiles[i].y; | |
124 | + | |
125 | + std::vector<int> xvals(width); //stores the width values | |
126 | + for (size_t i = 0; i < speroFiles.size(); i += height) //go through every "width" file and store the x coordinate | |
127 | + xvals[i / height] = speroFiles[i].x; | |
128 | + | |
129 | + std::sort(&yvals[0], &yvals[0] + yvals.size()); //sort both arrays of coordinates | |
130 | + std::sort(&xvals[0], &xvals[0] + xvals.size()); | |
131 | + | |
132 | + //create a mapping from the x and y coordinates to their indices | |
133 | + std::unordered_map<int, size_t> x2idx; | |
134 | + std::unordered_map<int, size_t> y2idx; | |
135 | + | |
136 | + for (size_t i = 0; i < height; i++) y2idx.insert(std::pair<int, size_t>(yvals[i], i)); //unordered maps now give an index for a coordinate | |
137 | + for (size_t i = 0; i < width; i++) x2idx.insert(std::pair<int, size_t>(xvals[i], i)); | |
138 | + | |
139 | + std::vector<stim::envi> M; //create an array of ENVI files in mosaic order | |
140 | + M.resize(speroFiles.size()); | |
141 | + | |
142 | + size_t xi, yi; | |
143 | + for (size_t i = 0; i < M.size(); i++) { //for each input file | |
144 | + xi = x2idx[speroFiles[i].x]; //get the x and y indices for this file's position in the mosaic | |
145 | + yi = y2idx[speroFiles[i].y]; | |
146 | + | |
147 | + size_t idx = yi * width + xi; | |
148 | + M[idx].open(speroFiles[i].headername.str_noext(), speroFiles[i].headername.str()); //open the ENVI file and set parameters | |
149 | + M[idx].close(); //close the file, since we can only open so many | |
150 | + } | |
151 | + | |
152 | + std::ofstream target(outfile.c_str(), std::ios::binary); //create a file to store the output | |
153 | + | |
154 | + stim::envi_header h = M[0].header; //create a header for the mosaic | |
155 | + h.samples *= width; | |
156 | + h.lines *= height; | |
157 | + size_t tile_width = M[0].header.samples; | |
158 | + size_t tile_height = M[0].header.lines; | |
159 | + | |
160 | + double progress = 0; | |
161 | + std::thread t1(progress_thread_double, &progress); //start the progress bar thread | |
162 | + | |
163 | + float* band = (float*)malloc(h.samples * h.lines * sizeof(float)); //allocate space for a band image | |
164 | + float* tile_band = (float*)malloc(tile_width * tile_height * sizeof(float)); | |
165 | + size_t dst, src; | |
166 | + | |
167 | + //reconstruct the array | |
168 | + for (size_t b = 0; b < h.bands; b++) { //for each band | |
169 | + for (size_t yi = 0; yi < height; yi++) { //for each tile in X and Y | |
170 | + for (size_t xi = 0; xi < width; xi++) { | |
171 | + M[yi * width + xi].open(); //open the tile | |
172 | + M[yi * width + xi].band_index(tile_band, b); //fill the tile_band pointer with the tile image at band b | |
173 | + for (size_t y = 0; y < tile_height; y++) { //copy the tile image to the destination band image | |
174 | + //dst = (yi * tile_height + tile_height - y - 1) * h.samples + xi * tile_width; | |
175 | + dst = ((height - yi - 1) * tile_height + y) * h.samples + xi * tile_width; | |
176 | + src = y * tile_width; | |
177 | + memcpy(band + dst, tile_band + src, sizeof(float) * tile_width); | |
178 | + } | |
179 | + | |
180 | + M[yi * width + xi].close(); //close the tile | |
181 | + | |
182 | + progress = (double)(b * height * width + yi * width + xi + 1) / (width * height * h.bands) * 100; //update the progress bar | |
183 | + } | |
184 | + } | |
185 | + target.write((char*)band, h.samples * h.lines * sizeof(float)); //write the entire band to the output image | |
186 | + } | |
187 | + | |
188 | + t1.join(); //wait for the thread to terminate | |
189 | + | |
190 | + target.close(); //close the output file | |
191 | + h.save(outfile + ".hdr"); //write the header | |
192 | + | |
193 | + free(band); | |
194 | +} | |
195 | + | |
196 | +void advertise() { | |
197 | + std::cout << std::endl << std::endl; | |
198 | + std::cout << "=========================================================================" << std::endl; | |
199 | + std::cout << "Thank you for using the SIPROC spectroscopic image processing toolkit!" << std::endl; | |
200 | + std::cout << "Scalable Tissue Imaging and Modeling (STIM) Lab, University of Houston" << std::endl; | |
201 | + std::cout << "Developers: Sam Saki, Ziqi He, David Mayerich, Brad Deutsch" << std::endl; | |
202 | + std::cout << "Source: https://github.com/stimlab/hsiproc.git" << std::endl; | |
203 | + std::cout << "This version has been compiled on " << __DATE__ << " at " << __TIME__ << std::endl; | |
204 | + std::cout << "=========================================================================" << std::endl << std::endl; | |
205 | + | |
206 | + std::cout << "Daylight SPERO mosaic assembly usage:" << std::endl; | |
207 | + std::cout << " >> spero directory/to/files mosaic" << std::endl; | |
208 | +} | |
209 | + | |
210 | +int main(int argc, char* argv[]) { | |
211 | + | |
212 | + args.add("help", "print help"); | |
213 | + args.parse(argc, argv); //parse the argument list | |
214 | + | |
215 | + if (args["help"]) { | |
216 | + std::cout << args.str() << std::endl; | |
217 | + exit(1); | |
218 | + } | |
219 | + std::string indir = "."; | |
220 | + std::string outfile = "mosaic"; | |
221 | + if (args.nargs() == 1) outfile = args.arg(0); //if only one argument is given, assume it is the output file | |
222 | + else if (args.nargs() >= 2) { //if two arguments are given | |
223 | + indir = args.arg(0); //the first argument is the directory | |
224 | + outfile = args.arg(1); //the second argument is the output file | |
225 | + } | |
226 | + std::cout << "SPERO mosaic assembly: " << indir << " --> " << outfile << std::endl; | |
227 | + mosaic_spero(indir, outfile); //call the SPERO mosaic function | |
228 | +} | |
0 | 229 | \ No newline at end of file | ... | ... |
1 | +++ a/src/view/hsiview.cpp | |
1 | +///KNOWN BUGS | |
2 | + | |
3 | +/// *) The mouse pointer position gets messed up if any of the band windows are resized | |
4 | +/// This is caused by not knowing which window is clicked when the mouse_band() callback is triggered. | |
5 | +/// If it's possible to get the window, just change the if(n == 0) code to reference the correct window and pull it outside the loop | |
6 | +/// *) Each spectrum should be displayed in a different color | |
7 | +/// *) ENVI files with different numbers of bands aren't supported | |
8 | +/// This can be fixed by changing everything in the HSIview code to deal with wavenumbers rather than bands | |
9 | + | |
10 | + | |
11 | +#include <iostream> | |
12 | + | |
13 | +#include <stim/parser/arguments.h> | |
14 | +#include <stim/envi/envi.h> | |
15 | +#include <stim/image/image.h> | |
16 | +#include <stim/visualization/colormap.h> | |
17 | +#include <stim/parser/filename.h> | |
18 | + | |
19 | +#ifdef _WIN32 | |
20 | + #include <GL/glew.h> | |
21 | +#endif | |
22 | + | |
23 | +#include <GL/glut.h> | |
24 | +#include <stim/gl/error.h> | |
25 | + | |
26 | +#define NN 5 | |
27 | + | |
28 | +size_t N; //number of open ENVI files | |
29 | + | |
30 | +stim::arglist args; //program arguments structure | |
31 | + | |
32 | +stim::envi ENVI[NN]; //global ENVI file being visualized | |
33 | +size_t SAMPLES; //dimensions of the loaded ENVI files | |
34 | +size_t LINES; | |
35 | +size_t BANDS[NN]; //number of bands in each spectrum | |
36 | +stim::image<unsigned char> band_image[NN]; //stores an image of the band | |
37 | +float* spectrum[NN]; //array stores the current spectrum | |
38 | +double* wavelengths[NN]; //array stores the independent variable for the spectrum (usually wavelength or frequency) | |
39 | +float sMax, sMin; //maximum value in the current spectrum | |
40 | +float wMin, wMax; //minimum and maximum independent spectral values | |
41 | + | |
42 | +float colorMin, colorMax; | |
43 | +bool colorManual = false; //control the color mapping manually | |
44 | + | |
45 | +size_t B[NN] = {0, 0}; //current band being visualized | |
46 | +double W = 0.0; //wavelength current visualized | |
47 | +size_t X, Y; //current pixel position | |
48 | + | |
49 | +double vFactor = 0.2; //fraction of the spectral window used as space above the spectrum to display numbers | |
50 | + | |
51 | +GLuint tex_id[NN]; | |
52 | + | |
53 | +int winBand[NN]; //Window identifier for the band image | |
54 | +int winSpectrum; //window identifier for the spectrum | |
55 | + | |
56 | +float colorMap[NN][3] = {{1, 1, 1}, {1, 0, 0}, {0, 1, 0}, {0, 0, 1}, {0, 1, 1}}; | |
57 | + | |
58 | +///Output software advertisement and instructions | |
59 | +void advertise(){ | |
60 | + //output advertisement | |
61 | + std::cout<<std::endl<<std::endl; | |
62 | + std::cout<<"========================================================================="<<std::endl; | |
63 | + std::cout<<"Thank you for using the HSIview spectroscopic image visualization software!"<<std::endl; | |
64 | + std::cout<<"Scalable Tissue Imaging and Modeling (STIM) Lab, University of Houston"<<std::endl; | |
65 | + std::cout<<"Developers: David Mayerich"<<std::endl; | |
66 | + std::cout<<"Source: https://github.com/stimlab/hsiproc.git"<<std::endl; | |
67 | + std::cout << "This version has been compiled on " << __DATE__ << " at " << __TIME__ << std::endl; | |
68 | + std::cout<<"========================================================================="<<std::endl<<std::endl; | |
69 | + std::cout<<std::endl<<"usage: hsiview input --option [A B C ...]"<<std::endl; | |
70 | + std::cout<<std::endl<<std::endl | |
71 | + << "examples:"<<std::endl | |
72 | + << " hsiview envifile"<<std::endl | |
73 | + << " Visualize the ENVI file 'envifile'"<<std::endl | |
74 | + ; | |
75 | + std::cout<<"LEFT click on a pixel to display the associated spectrum"<<std::endl; | |
76 | + std::cout<<"LEFT click on a position in the spectrum to display the associated band image"<<std::endl; | |
77 | + std::cout<<"MIDDLE click on the spectrum to turn manual color-mapping on/off"<<std::endl; | |
78 | + std::cout<<"\tSHIFT + LEFT click in the spectral window to set the minimum spectral value (blue)"<<std::endl; | |
79 | + std::cout<<"\tSHIFT + RIGHT click in the spectral window to set the maximum spectral value (red)"<<std::endl; | |
80 | + std::cout<<std::endl<<std::endl; | |
81 | + | |
82 | + std::cout<<args.str(); | |
83 | +} | |
84 | + | |
85 | +//sets an OpenGL viewport taking up the entire window | |
86 | +void glut_band_projection(){ | |
87 | + | |
88 | + glMatrixMode(GL_PROJECTION); //load the projection matrix for editing | |
89 | + glLoadIdentity(); //start with the identity matrix | |
90 | + int X = glutGet(GLUT_WINDOW_WIDTH); //use the whole screen for rendering | |
91 | + int Y = glutGet(GLUT_WINDOW_HEIGHT); | |
92 | + glViewport(0, 0, X, Y); //specify a viewport for the entire window | |
93 | + float aspect = (float)X / (float)Y; //calculate the aspect ratio | |
94 | + gluOrtho2D((double)0, (double)SAMPLES, (double)LINES, (double)0); //set up a perspective projection | |
95 | +} | |
96 | + | |
97 | +/// Render an image of the current band | |
98 | +void render_band(size_t n){ | |
99 | + glut_band_projection(); | |
100 | + | |
101 | + glMatrixMode(GL_MODELVIEW); | |
102 | + glLoadIdentity(); | |
103 | + | |
104 | + glClearColor(0, 0, 0, 0); | |
105 | + glClear(GL_COLOR_BUFFER_BIT); | |
106 | + | |
107 | + glEnable(GL_TEXTURE_2D); //enable texture mapping | |
108 | + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //texture map will be used as the network color | |
109 | + glBindTexture(GL_TEXTURE_2D, tex_id[n]); //bind the Brewer texture map | |
110 | + | |
111 | + glBegin(GL_QUADS); //draw the band image | |
112 | + glTexCoord2d(0, 0); | |
113 | + glVertex2d(0, 0); | |
114 | + glTexCoord2d(0, 1); | |
115 | + glVertex2d(0, (double)LINES); | |
116 | + glTexCoord2d(1, 1); | |
117 | + glVertex2d((double)SAMPLES, (double)LINES); | |
118 | + glTexCoord2d(1, 0); | |
119 | + glVertex2d((double)SAMPLES, 0); | |
120 | + glEnd(); | |
121 | + | |
122 | + //draw crosshairs | |
123 | + glDisable(GL_TEXTURE_2D); //disable the texture map so that it isn't rendered in the crosshairs | |
124 | + glColor3f(0.0f, 0.0f, 0.0f); //the crosshairs will be black | |
125 | + glBegin(GL_LINES); //draw two lines | |
126 | + glVertex2d(0, (double)Y + 0.5); | |
127 | + glVertex2d((double)SAMPLES, (double)Y + 0.5); | |
128 | + | |
129 | + glVertex2d((double)X + 0.5, (double)0); | |
130 | + glVertex2d((double)X + 0.5, (double)LINES); | |
131 | + glEnd(); //finish drawing the crosshairs | |
132 | + | |
133 | + glutSwapBuffers(); //swap the doubles | |
134 | +} | |
135 | + | |
136 | +void render_bands(){ | |
137 | + for(size_t n = 0; n < N; n++) | |
138 | + render_band(n); | |
139 | +} | |
140 | + | |
141 | +//Draw a number at the specified location | |
142 | +void draw_num(double num, double x, double y, void* font){ | |
143 | + glRasterPos2d(x, y); | |
144 | + | |
145 | + std::stringstream ss; //create a string stream | |
146 | + ss<<num; //store the spectral value in the stream | |
147 | + std::string str = ss.str(); //convert the stream to a string | |
148 | + for(size_t i = 0; i < str.length(); i++) //for each character in the string | |
149 | + glutBitmapCharacter(font, str[i]); //render that character | |
150 | +} | |
151 | + | |
152 | +/// Draw a spectrum | |
153 | +void draw_spectrum(size_t n){ | |
154 | + | |
155 | + //render the spectrum | |
156 | + //glColor3f(1.0, 1.0, 1.0); | |
157 | + glColor3f(colorMap[n][0], colorMap[n][1], colorMap[n][2]); | |
158 | + glBegin(GL_LINE_STRIP); | |
159 | + for(unsigned long long b = 0; b < BANDS[n]; b++) | |
160 | + glVertex2d((double)wavelengths[n][b], (double)spectrum[n][b]); | |
161 | + glEnd(); | |
162 | + | |
163 | + glColor3f(0.0,1.0,0.0); | |
164 | + draw_num((double)spectrum[n][B[n]], (double)W, (double)spectrum[n][B[n]], GLUT_BITMAP_TIMES_ROMAN_24); //render the current spectral value | |
165 | +} | |
166 | + | |
167 | +void render_spectra(){ | |
168 | + glutSetWindow(winSpectrum); //set the current window to the spectrum window | |
169 | + glClearColor(0, 0, 0, 0); //set the clear color | |
170 | + glClear(GL_COLOR_BUFFER_BIT); //clear the window | |
171 | + CHECK_OPENGL_ERROR | |
172 | + glMatrixMode(GL_PROJECTION); //load the projection matrix for editing | |
173 | + glLoadIdentity(); //start with the identity matrix | |
174 | + int X = glutGet(GLUT_WINDOW_WIDTH); //use the whole screen for rendering | |
175 | + int Y = glutGet(GLUT_WINDOW_HEIGHT); | |
176 | + glViewport(0, 0, X, Y); //specify a viewport for the entire window | |
177 | + CHECK_OPENGL_ERROR | |
178 | + if(sMin != sMax) | |
179 | + gluOrtho2D(wMin, wMax, (double)sMin, (double)sMax + (sMax - sMin) * vFactor); //set up a perspective projection | |
180 | + else | |
181 | + gluOrtho2D(wMin, wMax, (double)sMin - 1.0, (double)sMax + 1.0); | |
182 | + CHECK_OPENGL_ERROR | |
183 | + //render the zero line | |
184 | + glColor3f(0.0, 1.0, 1.0); | |
185 | + glBegin(GL_LINES); | |
186 | + glVertex2d(wMin, 0); | |
187 | + glVertex2d(wMax, 0); | |
188 | + glEnd(); | |
189 | + | |
190 | + for(size_t n = 0; n < N; n++) | |
191 | + draw_spectrum(n); | |
192 | + | |
193 | + if(colorManual){ //if manual color mapping is applied | |
194 | + glColor3f(1.0, 0.0, 0.0); //draw a red max line | |
195 | + glBegin(GL_LINES); | |
196 | + glVertex2d(wMin, colorMax); | |
197 | + glVertex2d(wMax, colorMax); | |
198 | + glEnd(); | |
199 | + glColor3f(0.0, 0.0, 1.0); //draw a blue min line | |
200 | + glBegin(GL_LINES); | |
201 | + glVertex2d(wMin, colorMin); | |
202 | + glVertex2d(wMax, colorMin); | |
203 | + glEnd(); | |
204 | + } | |
205 | + CHECK_OPENGL_ERROR | |
206 | + | |
207 | + //draw the band line | |
208 | + glColor3f(0.0, 1.0, 0.0); //the band line will be green | |
209 | + glBegin(GL_LINES); //draw a single band line | |
210 | + glVertex2d((double)W, (double)sMin); | |
211 | + glVertex2d((double)W, (double)sMax); | |
212 | + glEnd(); | |
213 | + | |
214 | + double pixelsize = (sMax - sMin) / glutGet(GLUT_WINDOW_HEIGHT); | |
215 | + //std::cout<<pixelsize<<std::endl; | |
216 | + draw_num(sMin, wMin, sMin, GLUT_BITMAP_TIMES_ROMAN_24); //render the minimum value | |
217 | + draw_num(sMax, wMin, sMax, GLUT_BITMAP_TIMES_ROMAN_24); //render the maximum value | |
218 | + | |
219 | + glutSwapBuffers(); //swap buffers | |
220 | +} | |
221 | + | |
222 | +void update_spectrum_minmax(){ | |
223 | + //update the global min and max values | |
224 | + wMin = wMax = (float)wavelengths[0][0]; //initialize the min and max independend variables | |
225 | + sMax = sMin = spectrum[0][0]; | |
226 | + for(size_t i = 0; i < N; i++){ //for each spectrum | |
227 | + //THIS STRANGE SYNTAX FOR std::min AND std::max are to get around pre-defined windows macros :-( | |
228 | + wMin = (std::min)(wMin, (float)wavelengths[i][0]); | |
229 | + wMax = (std::max)(wMax, (float)wavelengths[i][BANDS[i]-1]); | |
230 | + | |
231 | + for(size_t b = 0; b < BANDS[i]; b++){ //find the minimum and maximum spectral values | |
232 | + if(spectrum[i][b] > sMax) sMax = spectrum[i][b]; | |
233 | + if(spectrum[i][b] < sMin) sMin = spectrum[i][b]; | |
234 | + } | |
235 | + } | |
236 | +} | |
237 | +void update_spectrum(size_t n){ | |
238 | + | |
239 | + if(spectrum[n] == NULL) //if space hasn't been allocated for the spectrum | |
240 | + spectrum[n] = (float*) malloc(BANDS[n] * sizeof(float)); //allocate the space | |
241 | + if(wavelengths[n] == NULL) | |
242 | + wavelengths[n] = (double*) malloc(BANDS[n] * sizeof(double)); | |
243 | + if(ENVI[n].header.wavelength.size() == 0){ //if there are no wavelength values for the ENVI file | |
244 | + for(size_t i = 0; i < BANDS[n]; i++) //for each band | |
245 | + wavelengths[n][i] = (double)i; //save the band number as the wavelength | |
246 | + } | |
247 | + else | |
248 | + memcpy(wavelengths[n], &ENVI[n].header.wavelength[0], sizeof(double) * BANDS[n]); //copy the wavelength values | |
249 | + | |
250 | + ENVI[n].spectrum(spectrum[n], X, Y); //load the spectrum from the ENVI file | |
251 | + | |
252 | + glutSetWindow(winSpectrum); | |
253 | + glutPostRedisplay(); | |
254 | +} | |
255 | + | |
256 | +void update_spectra(){ | |
257 | + for(size_t n = 0; n < N; n++) | |
258 | + update_spectrum(n); | |
259 | + update_spectrum_minmax(); | |
260 | +} | |
261 | + | |
262 | +/// Update the band image displayed for ENVI file n | |
263 | +void update_band(size_t n){ | |
264 | + unsigned long long sx = SAMPLES; //calculate the image size | |
265 | + unsigned long long sy = LINES; | |
266 | + | |
267 | + float* buffer = NULL; //allocate a buffer | |
268 | + buffer = (float*)malloc( sx * sy * sizeof(float)); //allocate space for the band | |
269 | + std::vector<size_t> b_idx = ENVI[n].header.band_index(W); //get the bands closest to the current wavelength | |
270 | + if (b_idx.size() > 0) { //if a band exists | |
271 | + B[n] = b_idx[0]; | |
272 | + if (b_idx.size() > 1) { | |
273 | + double w0 = ENVI[n].header.wavelength[b_idx[0]]; //get the lower wavelength | |
274 | + double w1 = ENVI[n].header.wavelength[b_idx[1]]; //get the upper wavelength | |
275 | + if (abs(w1 - W) < abs(W - w0)) B[n] = b_idx[1]; //if the current wavelength is closer to the higher band, display the higher one | |
276 | + std::cout << "w0: " << w0 << std::endl; | |
277 | + std::cout << "w1: " << w1 << std::endl; | |
278 | + } | |
279 | + std::cout << "Display band: " << B[n] << std::endl; | |
280 | + } | |
281 | + ENVI[n].band_index(buffer, B[n]); //retrieve the band image | |
282 | + if(colorManual) | |
283 | + stim::cpu2cpu<float>(buffer, band_image[n].data(), sx * sy, colorMin, colorMax, stim::cmBrewer); | |
284 | + else | |
285 | + stim::cpu2cpu<float>(buffer, band_image[n].data(), sx * sy, stim::cmBrewer); //convert the band image to a color image | |
286 | + free(buffer); | |
287 | + | |
288 | + glutSetWindow(winBand[n]); //switch to the band window | |
289 | + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |
290 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //enable linear interpolation | |
291 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
292 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); //clamp the values at the minimum and maximum | |
293 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); | |
294 | + | |
295 | + //test to see if the texture can be accomodated | |
296 | + glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGB, (GLsizei)sx, (GLsizei)sy, 0, GL_RGB, GL_UNSIGNED_BYTE, band_image[n].data()); | |
297 | + int success; | |
298 | + glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &success); | |
299 | + if(success) | |
300 | + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)sx, (GLsizei)sy, 0, GL_RGB, GL_UNSIGNED_BYTE, band_image[n].data()); //upload the texture map to the GPU | |
301 | + else | |
302 | + std::cout << "Texture format not supported (likely the image size won't work with OpenGL - which sucks)" << std::endl; | |
303 | + CHECK_OPENGL_ERROR | |
304 | + | |
305 | + glutPostRedisplay(); //update the visualization | |
306 | +} | |
307 | + | |
308 | +/// Updates all band images | |
309 | +void update_bands(){ | |
310 | + for(size_t n = 0; n < N; n++) | |
311 | + update_band(n); | |
312 | +} | |
313 | + | |
314 | +/// Refresh band windows (update overlays and pixel locator positions) | |
315 | +void refresh_band(size_t n){ | |
316 | + glutSetWindow(winBand[n]); | |
317 | + glutPostRedisplay(); | |
318 | +} | |
319 | + | |
320 | +void refresh_bands(){ | |
321 | + for(size_t n = 0; n < N; n++) | |
322 | + refresh_band(n); | |
323 | +} | |
324 | + | |
325 | +/// Updates the spectrum when a new pixel position is selected in any band window | |
326 | +void mouse_band(int button, int state, int x, int y){ | |
327 | + | |
328 | + for(size_t n = 0; n < N; n++){ //for each band window | |
329 | + //translate from the window to the image | |
330 | + glutSetWindow(winBand[n]); //set the current window to the band window | |
331 | + if(n == 0){ //only evaluate the mouse position for the first window | |
332 | + X = (unsigned long long)(SAMPLES * (double)x / (double)glutGet(GLUT_WINDOW_WIDTH)); //calculate the ENVI x coordinate | |
333 | + Y = (unsigned long long)(LINES * (double)y / (double)glutGet(GLUT_WINDOW_HEIGHT)); //calculate the ENVI y coordinate | |
334 | + std::cout<<"("<<X<<", "<<Y<<")"<<std::endl; | |
335 | + } | |
336 | + | |
337 | + //update_spectrum(n); //update the current spectrum | |
338 | + refresh_band(n); | |
339 | + } | |
340 | + update_spectra(); | |
341 | +} | |
342 | + | |
343 | +/// Special keys for the band image | |
344 | +void special_band(int key, int x, int y){ | |
345 | + switch(key){ | |
346 | + case GLUT_KEY_UP: | |
347 | + Y--; | |
348 | + if(Y > LINES-1) Y = LINES-1; | |
349 | + break; | |
350 | + case GLUT_KEY_DOWN: | |
351 | + Y++; | |
352 | + if(Y > LINES-1) Y = 0; | |
353 | + break; | |
354 | + case GLUT_KEY_LEFT: | |
355 | + X--; | |
356 | + if(X > SAMPLES-1) X = SAMPLES-1; | |
357 | + break; | |
358 | + case GLUT_KEY_RIGHT: | |
359 | + X++; | |
360 | + if(X > SAMPLES-1) X = 0; | |
361 | + break; | |
362 | + } | |
363 | + refresh_bands(); | |
364 | + update_spectra(); | |
365 | +} | |
366 | + | |
367 | +/// Special keys for the band image | |
368 | +void key_spectrum(unsigned char key, int x, int y){ | |
369 | + | |
370 | + std::ofstream outfile("spectrum.csv"); | |
371 | + if(key == 's'){ | |
372 | + for(size_t b = 0; b < BANDS[0]; b++){ | |
373 | + if(b != 0) outfile<<","; | |
374 | + outfile<<spectrum[0][b]; | |
375 | + } | |
376 | + } | |
377 | + | |
378 | +} | |
379 | + | |
380 | +//find the current wavelength to be displayed | |
381 | +void mouse_spectrum(int button, int state, int x, int y){ | |
382 | + | |
383 | + //set manual colormap bounds | |
384 | + if(glutGetModifiers() == GLUT_ACTIVE_SHIFT){ | |
385 | + glutSetWindow(winSpectrum); | |
386 | + double a = (double)(glutGet(GLUT_WINDOW_HEIGHT) - y) / (double)glutGet(GLUT_WINDOW_HEIGHT); //calculate the click position in [0 1] | |
387 | + double aMax = sMax + (sMax - sMin) * vFactor; | |
388 | + double A = a * (aMax - sMin) + sMin; | |
389 | + if(button == GLUT_LEFT_BUTTON) | |
390 | + colorMin = (float)A; | |
391 | + if(button == GLUT_RIGHT_BUTTON) | |
392 | + colorMax = (float)A; | |
393 | + } | |
394 | + | |
395 | + //band selection (left button, unmodified) | |
396 | + else if(button == GLUT_LEFT_BUTTON){ //left button changes bands | |
397 | + glutSetWindow(winSpectrum); //retrieve data from the spectral window | |
398 | + W = (double)x / (double)glutGet(GLUT_WINDOW_WIDTH) * (wMax - wMin) + wMin; //calculate the wavelength to be visualized | |
399 | + std::cout<<"wavelength: "<<W<<std::endl; | |
400 | + } | |
401 | + | |
402 | + //turn manual color mapping on/off | |
403 | + else if(button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) | |
404 | + colorManual = !colorManual; //swap the colorManual flag, turning manual color mapping on or off | |
405 | + | |
406 | + update_bands(); | |
407 | + update_spectra(); | |
408 | +} | |
409 | + | |
410 | +void glut_motion(int x, int y){ | |
411 | +} | |
412 | + | |
413 | +void texture_initialize(size_t n){ | |
414 | + unsigned long long sx = SAMPLES; //calculate the image size | |
415 | + unsigned long long sy = LINES; | |
416 | + | |
417 | + band_image[n] = stim::image<unsigned char>(sx, sy, 3); //allocate space for the band visualization image | |
418 | + | |
419 | + glGenTextures(1, &tex_id[n]); //generate a texture map name | |
420 | + glBindTexture(GL_TEXTURE_2D, tex_id[n]); //bind the texture map | |
421 | +} | |
422 | + | |
423 | +void glut_initialize(std::string filename){ | |
424 | + | |
425 | + int myargc = 1; //GLUT requires arguments, so create some bogus ones | |
426 | + char* myargv[1]; | |
427 | + myargv[0] = (char*)malloc(1); | |
428 | + myargv[0][0] = 'h'; | |
429 | + | |
430 | + glutInit(&myargc, myargv); //pass bogus arguments to glutInit() | |
431 | + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); //generate a color buffer, depth buffer, and enable double buffering | |
432 | + | |
433 | + for(size_t n = 0; n < N; n++){ | |
434 | + glutInitWindowPosition(100,100); //set the initial window position | |
435 | + glutInitWindowSize(320,320); //set the initial window size | |
436 | + winBand[n] = glutCreateWindow((filename + " - HSIview - STIM Lab, UH").c_str()); //set the dialog box title | |
437 | + glutDisplayFunc(render_bands); //function executed for rendering - renders networks | |
438 | + glutMouseFunc(mouse_band); //executed on a mouse click - sets starting mouse positions for rotations | |
439 | + glutMotionFunc(glut_motion); //executed when the mouse is moved while a button is pressed | |
440 | + glutSpecialFunc(special_band); //special keys pressed when the band image is selected | |
441 | + texture_initialize(n); //set up texture mapping (create texture maps, enable features) | |
442 | + } | |
443 | + | |
444 | + glutInitWindowPosition(400,500); //set the initial window position | |
445 | + glutInitWindowSize(960,320); //set the initial window size | |
446 | + winSpectrum = glutCreateWindow("Spectrum"); | |
447 | + glutMouseFunc(mouse_spectrum); | |
448 | + glutDisplayFunc(render_spectra); | |
449 | + glutKeyboardFunc(key_spectrum); | |
450 | + | |
451 | +#ifdef _WIN32 | |
452 | + GLenum err = glewInit(); //initialize GLEW (necessary for Windows) | |
453 | + if (GLEW_OK != err){ //eror with GLEW | |
454 | + std::cout<<"Error with GLEW: "<<glewGetErrorString(err)<<std::endl; | |
455 | + exit(1); | |
456 | + } | |
457 | +#endif | |
458 | + | |
459 | +} | |
460 | + | |
461 | +int main(int argc, char* argv[]){ | |
462 | + | |
463 | + args.add("help", "prints this help text"); | |
464 | + args.add("agilent", "parse the input file(s) as Agilent binary files"); | |
465 | + | |
466 | + args.parse(argc, argv); //parse the input arguments | |
467 | + | |
468 | + //get the number of input files to display | |
469 | + N = args.nargs(); | |
470 | + | |
471 | + if(N > NN){ | |
472 | + std::cout<<"ERROR - HSIview cannot currently support more than "<<NN<<" simultaneous files."<<std::endl; | |
473 | + exit(1); | |
474 | + } | |
475 | + | |
476 | + if(args["help"].is_set() || N == 0){ | |
477 | + advertise(); | |
478 | + exit(1); | |
479 | + } | |
480 | + | |
481 | + | |
482 | + | |
483 | + for(size_t n = 0; n < N; n++){ | |
484 | + stim::filename fname = args.arg(n); //get the file name string and store it as a stim::filename | |
485 | + std::string envifile; | |
486 | + std::string enviheader; | |
487 | + if(args["agilent"].is_set()) | |
488 | + ENVI[n].open_agilent(args.arg(n)); | |
489 | + else if(fname.extension() == "drd" || //Agilent binary files: DMD, DRD, SEQ, DAT | |
490 | + fname.extension() == "dmd" || | |
491 | + fname.extension() == "seq" || | |
492 | + fname.extension() == "dat") | |
493 | + ENVI[n].open_agilent(fname.str()); | |
494 | + else if (fname.extension() == "hdr") { | |
495 | + envifile = fname.extension("").str(); | |
496 | + enviheader = fname.str(); | |
497 | + } | |
498 | + else { | |
499 | + envifile = args.arg(n); | |
500 | + enviheader = args.arg(n) + ".hdr"; | |
501 | + } | |
502 | + if (!ENVI[n].open(envifile, enviheader, stim::io_in)) { | |
503 | + std::cout << "ERROR opening ENVI file " << n << ": " << args.arg(n) << std::endl; | |
504 | + exit(1); | |
505 | + } | |
506 | + BANDS[n] = ENVI[n].header.bands; | |
507 | + } | |
508 | + | |
509 | + SAMPLES = ENVI[0].header.samples; | |
510 | + LINES = ENVI[0].header.lines; | |
511 | + | |
512 | + | |
513 | + | |
514 | + glut_initialize(args.arg(0)); //create a GLUT window | |
515 | + | |
516 | + //make sure that the image size is supported | |
517 | + GLint max_tex; | |
518 | + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex); | |
519 | + CHECK_OPENGL_ERROR | |
520 | + if(SAMPLES > max_tex || LINES > max_tex){ | |
521 | + std::cout<<"ERROR: image too large for OpenGL texture support. Maximum texture size is: "<<max_tex<<std::endl; | |
522 | + exit(1); | |
523 | + } | |
524 | + | |
525 | + | |
526 | + W = (wMax - wMin)/2.0; | |
527 | + update_bands(); //set the initial band image to the middle band | |
528 | + | |
529 | + X = SAMPLES/2; //initialize to the center pixel | |
530 | + Y = LINES/2; | |
531 | + update_spectra(); //update the pixel position and spectrum | |
532 | + glutMainLoop(); | |
533 | + ENVI[0].close(); | |
534 | +} | ... | ... |