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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | +} |