Commit 5f3cba022a184dcd2df3df174e49c6ba1566ad2c

Authored by David Mayerich
0 parents

initial public commit

.gitignore 0 โ†’ 100644
  1 +++ a/.gitignore
  1 +html/*
  2 +latex/*
0 3 \ No newline at end of file
... ...
.gitmodules 0 โ†’ 100644
  1 +++ a/.gitmodules
  1 +[submodule "CImg"]
  2 + path = CImg
  3 + url = http://git.code.sf.net/p/cimg/source
  4 +[submodule "stimlib"]
  5 + path = stimlib
  6 + url = git@git.stim.ee.uh.edu:codebase/stimlib.git
... ...
CMakeLists.txt 0 โ†’ 100644
  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 +
... ...
Doxyfile 0 โ†’ 100644
  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 +
... ...
FindFANN.cmake 0 โ†’ 100644
  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()
... ...
FindGLEW.cmake 0 โ†’ 100644
  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 ()
... ...
FindGLUT.cmake 0 โ†’ 100644
  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 + )
... ...
FindLAPACKE.cmake 0 โ†’ 100644
  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)
... ...
FindSTIM.cmake 0 โ†’ 100644
  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)
... ...
LICENSE.txt 0 โ†’ 100644
  1 +++ a/LICENSE.txt
  1 +<<<<<<< HEAD
  2 +Copyright (c) 2014, David Mayerich
  3 +=======
  4 +Copyright (c) 2009, David Mayerich
  5 +>>>>>>> a18fe1629f7950f34c604fa4ef6ae0c882efa3a5
  6 +All rights reserved.
  7 +
  8 +Redistribution and use in source and binary forms, with or without
  9 +modification, are permitted provided that the following conditions are met:
  10 +
  11 +1. Redistributions of source code must retain the above copyright notice, this
  12 + list of conditions and the following disclaimer.
  13 +2. Redistributions in binary form must reproduce the above copyright notice,
  14 + this list of conditions and the following disclaimer in the documentation
  15 + and/or other materials provided with the distribution.
  16 +
  17 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  18 +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19 +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20 +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  21 +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22 +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23 +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  24 +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  26 +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27 +
  28 +The views and conclusions contained in the software and documentation are those
  29 +of the authors and should not be interpreted as representing official policies,
  30 +either expressed or implied, of the FreeBSD Project.
0 31 \ No newline at end of file
... ...
README.md 0 โ†’ 100644
  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)
... ...
matlab/LoadAgilent.m 0 โ†’ 100644
  1 +++ a/matlab/LoadAgilent.m
  1 +%Loads a standard Agilent ResPro binary file (DMD, DRD, SEQ, etc)
  2 +% Scalable Tissue Imaging and Modeling Laboratory
  3 +% University of Houston
  4 +% developer: David Mayerich (mayerich@uh.edu)
  5 +
  6 +function S = stimLoadAgilent(filename)
  7 +
  8 + fid = fopen(filename);
  9 + fseek(fid, 9, 'bof');
  10 + Z = fread(fid, 1, 'uint16');
  11 + fseek(fid, 13, 'cof');
  12 + X = fread(fid, 1, 'uint16');
  13 + Y = fread(fid, 1, 'uint16');
  14 +
  15 + fseek(fid, 1020, 'bof');
  16 +
  17 + S = reshape(fread(fid, [X, Y * Z], 'float32'), [X, Y, Z]);
  18 +
  19 +
0 20 \ No newline at end of file
... ...
matlab/LoadENVI.m 0 โ†’ 100644
  1 +++ a/matlab/LoadENVI.m
  1 +%loads an ENVI file without any manipulation (changing orientation)
  2 +% Scalable Tissue Imaging and Modeling Laboratory
  3 +% University of Houston
  4 +% developer: David Mayerich (mayerich@uh.edu)
  5 +
  6 +function M = enviLoadRaw(filename, headername)
  7 +
  8 + if nargin == 1
  9 + headername = [filename '.hdr'];
  10 + end
  11 +
  12 + h = enviLoadHeader(headername);
  13 +
  14 + if strcmp(h.interleave, 'bsq')
  15 + X = h.samples;
  16 + Y = h.lines;
  17 + Z = h.bands;
  18 + elseif strcmp(h.interleave, 'bil')
  19 + X = h.samples;
  20 + Y = h.bands;
  21 + Z = h.lines;
  22 + else
  23 + X = h.bands;
  24 + Y = h.samples;
  25 + Z = h.lines;
  26 + end
  27 +
  28 + fid = fopen(filename);
  29 + M = fread(fid, [X, Y*Z], '*float32');
  30 + M = reshape(M, [X, Y, Z]);
  31 +
  32 + fclose(fid);
0 33 \ No newline at end of file
... ...
python/train-metrics.py 0 โ†’ 100644
  1 +++ a/python/train-metrics.py
  1 +import sys, string, os, subprocess
  2 +
  3 +os.system("cls")
  4 +
  5 +infile = sys.argv[1]
  6 +
  7 +A = "supervised-class/class_coll.png "
  8 +B = "supervised-class/class_epith.png "
  9 +C = "supervised-class/class_fibro.png "
  10 +D = "supervised-class/class_lymph.png "
  11 +E = "supervised-class/class_myo.png "
  12 +F = "supervised-class/class_necrosis.png "
  13 +G = "supervised-class/class_blood.png "
  14 +
  15 +Ca = "magenta "
  16 +Cb = "lime "
  17 +Cc = "pink "
  18 +Cd = "purple "
  19 +Ce = "yellow "
  20 +Cf = "orange "
  21 +Cg = "maroon "
  22 +
  23 +#project to metrics
  24 +subprocess.call("hsiproc " + infile + " " + infile + "-met --metrics metrics.txt")
  25 +
  26 +#create a mask to remove bad pixels
  27 +subprocess.call("hsiproc " + infile + "-met " + "finite.bmp --mask-finite")
  28 +subprocess.call("hsiproc " + infile + "-met " + infile + "-mask --apply-mask finite.bmp")
  29 +
  30 +#Baseline correction using a set of wavenumber points specified in baseline.txt
  31 +subprocess.call("hsiclass " + infile + "-mask classifier.rf --train " + A + B + C + D + E + F + G + "--verbose")
  32 +
  33 +#convert to BIP for speed
  34 +subprocess.call("hsiproc " + infile + "-mask " + infile + "-bip --convert bip")
  35 +
  36 +#classify the entire image
  37 +subprocess.call("hsiclass " + infile + "-bip " + infile + "-class.bmp " + "--classify classifier.rf --colors " + Ca + Cb + Cc + Cd + Ce + Cf + Cg + "--mask mask.bmp --verbose")
0 38 \ No newline at end of file
... ...
python/train-pca.py 0 โ†’ 100644
  1 +++ a/python/train-pca.py
  1 +import sys, string, os, subprocess
  2 +
  3 +os.system("cls")
  4 +
  5 +infile = sys.argv[1]
  6 +
  7 +A = "class/coll.bmp "
  8 +B = "class/epith.bmp "
  9 +C = "class/fibro.bmp "
  10 +D = "class/lymph.bmp "
  11 +E = "class/myo.bmp "
  12 +F = "class/necrosis.bmp "
  13 +G = "class/blood.bmp "
  14 +
  15 +Ca = "magenta "
  16 +Cb = "lime "
  17 +Cc = "pink "
  18 +Cd = "purple "
  19 +Ce = "yellow "
  20 +Cf = "orange "
  21 +Cg = "maroon "
  22 +
  23 +#Baseline correction using a set of wavenumber points specified in baseline.txt
  24 +subprocess.call("hsiproc " + infile + " " + infile + "-base --baseline baseline.txt")
  25 +
  26 +#Create a mask to be used later for PCA
  27 +subprocess.call("hsiproc " + infile + "-base mask.bmp --build-mask 1650 0.1")
  28 +
  29 +#Convert to a BIP file. This is generally the fastest file to use, algorithmically.
  30 +subprocess.call("hsiproc " + infile + "-base " + infile + "-bip --convert bip")
  31 +
  32 +#sift
  33 +subprocess.call("hsiproc " + infile + "-bip " + infile + "-sift --sift mask.bmp")
  34 +
  35 +#Normalize to Amide I
  36 +subprocess.call("hsiproc " + infile + "-sift " + infile + "-norm --normalize 1650")
  37 +
  38 +#Calculate the principle components
  39 +subprocess.call("hsiproc " + infile + "-norm " + infile + ".sta --pca")
  40 +
  41 +#project onto the PCs
  42 +subprocess.call("hsiproc " + infile + "-norm " + infile + "-pca --project pca.sta 30")
  43 +
  44 +#unsift
  45 +subprocess.call("hsiproc " + infile + "-pca " + infile + "-unsift --unsift mask.bmp")
  46 +
  47 +#convert back to BSQ
  48 +subprocess.call("hsiproc " + infile + "-unsift " + infile + "-final --convert bsq")
  49 +
  50 +#Baseline correction using a set of wavenumber points specified in baseline.txt
  51 +subprocess.call("hsiclass " + infile + "-final " + infile + ".rf --train " + A + B + C + D + E + F + G)
  52 +
  53 +#classify the entire image
  54 +subprocess.call("hsiclass " + infile + "-final " + infile + "-class.bmp " + "--classify classifier.rf --colors " + Ca + Cb + Cc + Cd + Ce + Cf + Cg + "--mask mask.bmp --verbose")
0 55 \ No newline at end of file
... ...
python/validate.py 0 โ†’ 100644
  1 +++ a/python/validate.py
  1 +import sys, string, os, subprocess
  2 +
  3 +os.system("cls")
  4 +
  5 +infile = sys.argv[1]
  6 +
  7 +Ca = "magenta "
  8 +Cb = "lime "
  9 +Cc = "pink "
  10 +Cd = "purple "
  11 +Ce = "yellow "
  12 +Cf = "orange "
  13 +Cg = "maroon "
  14 +
  15 +#Baseline correction using a set of wavenumber points specified in baseline.txt
  16 +subprocess.call("hsiproc " + infile + " " + infile + "-base --baseline baseline.txt")
  17 +
  18 +#Create a mask to be used later for PCA
  19 +subprocess.call("hsiproc " + infile + "-base mask.bmp --build-mask 1650 0.1")
  20 +
  21 +#Convert to a BIP file. This is generally the fastest file to use, algorithmically.
  22 +subprocess.call("hsiproc " + infile + "-base " + infile + "-bip --convert bip")
  23 +
  24 +#sift
  25 +subprocess.call("hsiproc " + infile + "-bip " + infile + "-sift --sift mask.bmp")
  26 +
  27 +#Normalize to Amide I
  28 +subprocess.call("hsiproc " + infile + "-sift " + infile + "-norm --normalize 1650")
  29 +
  30 +#project onto pre-computed PCs
  31 +subprocess.call("hsiproc " + infile + "-norm " + infile + "-pca --project pca.sta 30")
  32 +
  33 +#unsift
  34 +subprocess.call("hsiproc " + infile + "-pca " + infile + "-final --unsift mask.bmp")
  35 +
  36 +#classify the entire image
  37 +subprocess.call("hsiclass " + infile + "-final " + infile + "-class.bmp " + "--classify classifier.rf --colors " + Ca + Cb + Cc + Cd + Ce + Cf + Cg + "--mask mask.bmp --verbose")
0 38 \ No newline at end of file
... ...
src/cary-ftir/cary-ftir.cpp 0 โ†’ 100644
  1 +++ a/src/cary-ftir/cary-ftir.cpp
  1 +//#define _CRTDBG_MAP_ALLOC
  2 +//#include <stdlib.h>
  3 +//#include <crtdbg.h>
  4 +
  5 +#include <iostream>
  6 +
  7 +#include <stim/parser/arguments.h>
  8 +#include <stim/envi/agilent_binary.h>
  9 +#include <stim/parser/filename.h>
  10 +
  11 +stim::arglist args; //generate a list of accepted arguments
  12 +
  13 +#include <thread>
  14 +void progress_thread_double(double* e); //progress bar threaded function
  15 +
  16 +bool fft = false; //perform an FFT before storing
  17 +double wn_low, wn_high;
  18 +float elwn;
  19 +int udr;
  20 +
  21 +bool absorbance = false;
  22 +stim::agilent_binary<float> background; //store the background data
  23 +
  24 +bool crop_samples = false;
  25 +size_t n_samples;
  26 +
  27 +
  28 +void mosaic_coord(unsigned int &x, unsigned int &y, stim::filename dmd_filename) {
  29 +
  30 + //get the file prefix
  31 + std::string prefix = dmd_filename.get_prefix();
  32 +
  33 + //these files are in the format:
  34 + // ???????????_xxxxx_yyyyy.dmd
  35 +
  36 + //find the position of the last underscore
  37 + size_t y_start = prefix.find_last_of("_");
  38 + //remove all values between x_start and the end of the string
  39 + std::string y_string = prefix.substr(y_start + 1);
  40 +
  41 + y = atoi(y_string.c_str());
  42 +
  43 + //crop out the x coordinate and the last underscore
  44 + prefix = prefix.substr(0, y_start);
  45 +
  46 + //find the y coordinate using the same method as above
  47 + size_t x_start = prefix.find_last_of("_");
  48 + std::string x_string = prefix.substr(x_start + 1);
  49 + x = atoi(x_string.c_str());
  50 +}
  51 + //Use the file list to find the number of tiles along each dimension of the mosaic
  52 +void mosaic_size(unsigned int &sx, unsigned int &sy, std::vector<stim::filename> dmd_list) {
  53 + sx = sy = 0;
  54 +
  55 + unsigned int xi, yi;
  56 +
  57 + //for each dmd file
  58 + for (unsigned int i = 0; i < dmd_list.size(); i++) {
  59 +
  60 + //find the coordinate of the tile represented by this file
  61 + mosaic_coord(xi, yi, dmd_list[i]);
  62 +
  63 + //if the coordinate is larger than the current max, store it as the current max
  64 + if (xi > sx) sx = xi;
  65 + if (yi > sy) sy = yi;
  66 + }
  67 +
  68 + //add 1 to reflect that the indexing starts at 0
  69 + sx++; sy++;
  70 +}
  71 +
  72 +void save_mosaic(std::vector<stim::filename> tile_list, std::string outfile, stim::agilent_binary<float>* background = NULL) {
  73 +
  74 + stim::agilent_binary<float> binfile(tile_list[0]); //load the first agilent binary file
  75 + size_t ds = binfile.dim(0); //get the detector size
  76 +
  77 + unsigned int mx, my;
  78 + mosaic_size(mx, my, tile_list); //calculate the mosaic size
  79 + std::cout << "Building a ["<<mx<<" x "<<my<<"] mosaic with a detector size of (" << ds << " x " << ds <<") pixels"<< std::endl;
  80 + std::cout << "Mosaic size: " << mx << " " << my << std::endl; //output the mosaic size
  81 +
  82 + std::ofstream out(outfile, std::ios::binary); //open a binary file for writing
  83 +
  84 + size_t nxo = mx * ds; //number of output pixels along x
  85 + size_t nyo = my * ds; //number of output pixels along y
  86 + size_t nbo;
  87 +
  88 + size_t bytes_tile_band = ds * ds * sizeof(float); //number of bytes in a tile band
  89 + size_t bytes_out_band = bytes_tile_band * mx * my; //number of bytes in an output image band
  90 +
  91 + double progress = 0.0;
  92 + std::thread t1(progress_thread_double, &progress); //start the progress bar thread
  93 + size_t xo, yo, io;
  94 + size_t ii;
  95 + stim::envi_header header;
  96 + bool header_flag = true;
  97 + for (size_t ty = 0; ty < my; ty++) {
  98 + for (size_t tx = 0; tx < mx; tx++) {
  99 + xo = tx * ds; //calculate the x output position for the current tile
  100 + stim::agilent_binary<float> I(tile_list[tx * my + ty].str());
  101 + if (crop_samples) I.crop(n_samples); //crop samples if necessary to reduce spectral resolution
  102 + if (fft) I = I.fft(wn_low, wn_high, elwn, udr); //if an FFT is requested, perform it
  103 + if (background) I.absorbance(background); //if the user provides a background file
  104 + if (header_flag) {
  105 + header = I.create_header();
  106 + header_flag = false;
  107 + }
  108 + nbo = I.dim(2); //get the number of bands in the output image
  109 + for (size_t b = 0; b < nbo; b++) { //for each band in the input
  110 + for (size_t yi = 0; yi < ds; yi++) { //for each line in the input image
  111 + yo = ty * ds + ds - yi - 1; //calculate the y output position
  112 + io = (b * nxo * nyo + yo * nxo + xo); //calculate the output position as a 1d index
  113 + ii = (b * ds * ds + yi * ds); //calculate the input position as a 1d index
  114 + out.seekp(io * sizeof(float)); //seek to the correct output location
  115 + out.write(I.data() + ii * sizeof(float), ds * sizeof(float)); //copy the line from input to output
  116 + }
  117 + }
  118 + progress = (double)(ty * mx + tx + 1) / (double)(mx * my) * 100;
  119 + }
  120 + }
  121 + out.close();
  122 + t1.join(); //wait for the progress bar thread to finish (it probably already is)
  123 +
  124 + header.samples = mx * ds;
  125 + header.lines = my * ds;
  126 + header.save(outfile + ".hdr");
  127 +}
  128 +
  129 +void output_files(std::vector<stim::filename> infiles, std::string outfile) {
  130 + if (infiles.size() == 1) {
  131 + std::cout << "source file: " << infiles[0].str() << std::endl;
  132 + }
  133 + else {
  134 + std::cout << "number of input files: " << infiles.size() << std::endl;
  135 + }
  136 + std::cout << "destination file: " << outfile << std::endl;
  137 +}
  138 +
  139 +int main(int argc, char* argv[]){
  140 +
  141 + args.add("help", "print help");
  142 + args.add("spacing", "specify the spectral resolution", "", "positive integer specifying wavenumber spacing");
  143 + args.add("fft", "perform a fourier transform of the data before assembling the mosaic", "", "optional wavenumber range (override UDR), ex: 900 3500");
  144 + args.add("udr", "udr filter used for imaging", "4", "(4 or 8 supported)");
  145 + args.add("elwn", "ELWN tuning number", "15798.0039", "HeNe sampling rate (in cm^(-1))");
  146 + args.add("background", "specify a background file for measuring absorbance", "", "filename.seq");
  147 + args.add("cuda", "specify a CUDA device for the FFT", "0", "index of CUDA device (-1 forces CPU only)");
  148 + args.parse(argc, argv); //parse the argument list
  149 +
  150 + if (args.nargs() < 2 || args["help"]) {
  151 + std::cout << "Usage: " << std::endl<<std::endl;
  152 + std::cout << "\tGenerate an ENVI mosaic from a set of tiles produced by a Cary FTIR imaging system:" << std::endl;
  153 + std::cout << "\t\t>> cary-ftir input_files/*.dmd output_mosaic" << std::endl << std::endl;
  154 + std::cout << args.str() << std::endl;
  155 + exit(1);
  156 + }
  157 +
  158 + stim::filename infile(args.arg(0));
  159 + std::vector<stim::filename> in; //create a list of input files
  160 + if (args.nargs() == 2) {
  161 + if (infile.wildcards()) in = infile.get_list(); //if a wildcard is specified, get the file list
  162 + else in.push_back(infile); //if a single file is specified, create a file list of 1
  163 + }
  164 + //if the user specifies several files on the command line
  165 + else {
  166 + for (size_t f = 0; f < args.nargs() - 1; f++) { //for each file specified
  167 + in.push_back(args.arg(f)); //add the file to the file list
  168 + }
  169 + }
  170 +
  171 + std::string outfilename = args.arg(args.nargs() - 1); //get the output file
  172 +
  173 + output_files(in, outfilename);
  174 +
  175 + udr = args["udr"].as_int(); //save the UDR filter type
  176 + if (udr == 4) {
  177 + wn_low = 900;
  178 + wn_high = 3900;
  179 + }
  180 + else {
  181 + wn_low = 800;
  182 + wn_high = 1900;
  183 + }
  184 +
  185 + if (args["fft"].is_set()) {
  186 + fft = true; //set the fft flag to true
  187 +
  188 + if (args["fft"].nargs() >= 1) {
  189 + if(args["fft"].is_num(0))
  190 + wn_low = args["fft"].as_float(0);
  191 + else {
  192 + std::cout << "ERROR: FFT output range must be a number: " << args["fft"].as_string(0) << std::endl;
  193 + return 1;
  194 + }
  195 + }
  196 + if (args["fft"].nargs() >= 2) {
  197 + if (args["fft"].is_num(1))
  198 + wn_high = args["fft"].as_float(1);
  199 + else {
  200 + std::cout << "ERROR: FFT output range must be a number: " << args["fft"].as_string(1) << std::endl;
  201 + return 1;
  202 + }
  203 + }
  204 +
  205 + }
  206 +
  207 + elwn = (float)args["elwn"].as_float();
  208 +
  209 + if (args["spacing"]) {
  210 + double di = (1.0 / elwn) * ((double)udr / 2.0); //calculate the interferogram spacing
  211 + double df = (double)args["spacing"].as_int(); //get the desired spectral spacing
  212 + n_samples = (size_t)std::ceil(1.0 / (di * df)); //calculate the number of samples required
  213 + std::cout << "Override default spectral spacing with " << df << " cm^(-1) by cropping to " << n_samples << " samples" << std::endl;
  214 + crop_samples = true;
  215 + }
  216 +
  217 + if (args["background"]) {
  218 + if (!args["fft"]) {
  219 + std::cout << "ERROR: using a background requires calculating an FFT - use the --fft option as well" << std::endl;
  220 + exit(1);
  221 + }
  222 + stim::agilent_binary<float> background(args["background"].as_string());
  223 + if (background) {
  224 + if (crop_samples) background.crop(n_samples); //crop the samples if necessary
  225 + background = background.fft(wn_low, wn_high, elwn, udr);
  226 + save_mosaic(in, outfilename, &background);
  227 + //absorbance = true;
  228 + }
  229 + else {
  230 + std::cout << "ERROR loading background file: " << args["background"].as_string() << std::endl;
  231 + return 1;
  232 + }
  233 + }
  234 + else {
  235 + save_mosaic(in, outfilename);
  236 + }
  237 +
  238 +// _CrtDumpMemoryLeaks();
  239 +}
0 240 \ No newline at end of file
... ...
src/class_ann.h 0 โ†’ 100644
  1 +++ a/src/class_ann.h
  1 +//OpenCV
  2 +#include <opencv2/opencv.hpp>
  3 +
  4 +#include "progress_thread.h"
  5 +
  6 +extern size_t X, Y, B;
  7 +
  8 +//function for training a random forest classifier
  9 +void train_ann(CvANN_MLP* ann, cv::Mat &trainF, cv::Mat &trainR, std::vector<int> hidden, int iters, double epsilon, bool VERBOSE = false){
  10 +
  11 + //ANN criteria for termination
  12 + CvTermCriteria criter;
  13 + criter.max_iter = iters;
  14 + criter.epsilon = epsilon;
  15 + criter.type = CV_TERMCRIT_ITER | CV_TERMCRIT_EPS;
  16 +
  17 + //ANN parameters
  18 + CvANN_MLP_TrainParams params;
  19 + params.train_method = CvANN_MLP_TrainParams::BACKPROP;
  20 + params.bp_dw_scale = 0.05f;
  21 + params.bp_moment_scale = 0.05f;
  22 + params.term_crit = criter; //termination criteria
  23 +
  24 + cv::Mat layers = cv::Mat((int)hidden.size() + 2, 1, CV_32SC1); //create one input layer, one output layer, and n (specified) hidden layers
  25 +
  26 +
  27 + layers.row(0) = cv::Scalar(trainF.cols); //the first layer is based on the number of inputs
  28 + for(size_t l = 0; l < hidden.size(); l++){ //for each hidden layer
  29 + layers.row((int)l + 1) = cv::Scalar(hidden[l]); //specify the number of hidden nodes
  30 + }
  31 + layers.row((int)hidden.size() + 1) = cv::Scalar(trainR.cols); //the output layer is equal to the number of responses per pixel
  32 +
  33 + std::cout<<"Creating an MLP with the structure: "<<std::endl<<"\t";
  34 +
  35 + std::cout<<"(in) "<<layers.at<int>(0, 0);
  36 + for(size_t l = 1; l < layers.rows - 1; l++)
  37 + std::cout<<" "<<layers.at<int>((int)l, 0);
  38 + std::cout<<" "<<layers.at<int>(layers.rows-1, 0)<<" (out)"<<std::endl;
  39 + ann->create(layers); //create the neural network given the architecture
  40 +
  41 + std::cout<<"Training..."<<std::endl;
  42 + ann->train(trainF, trainR, cv::Mat(), cv::Mat(), params); //call the ANN training algorithm
  43 + std::cout<<"done..."<<std::endl;
  44 +
  45 + ///// TEMPORARY - WILL BE DELETED IN THE ACTUAL IMPLEMENTATION ///////////////
  46 + cv::Mat predicted(trainR.rows, 1, CV_32F); //allocate space for a predicted response
  47 +
  48 + stim::image<unsigned char> test(X, Y, 3); //create a 3-channel (color) image
  49 + test = 0;
  50 + for(size_t y = 0; y < Y; y++){ //for each pixel in the image
  51 + for(size_t x = 0; x < X; x++){
  52 + cv::Mat response(3, 1, CV_32FC1);
  53 + cv::Mat sample = trainF.row((int)(y * X + x)); //load the corresponding value from the training array
  54 +
  55 + ann->predict(sample, response); //predict the response for this pixel
  56 + test(x, y, 0) = (unsigned char)(response.at<float>(0, 0) * 255); //save the response in the color image (make sure to re-scale the values to [0, 255])
  57 + test(x, y, 1) = (unsigned char)(response.at<float>(0, 1) * 255);
  58 + test(x, y, 2) = (unsigned char)(response.at<float>(0, 2) * 255);
  59 + }
  60 + }
  61 + test.save("response.bmp"); //save the response
  62 +}
0 63 \ No newline at end of file
... ...
src/class_bay.h 0 โ†’ 100644
  1 +++ a/src/class_bay.h
  1 +//OpenCV
  2 +#include <opencv2/opencv.hpp>
  3 +
  4 +#include "progress_thread.h"
  5 +
  6 +double progress = 0.0;
  7 +
  8 +//create a custom classifier to access the number of classes (OpenCV protected variable)
  9 +class BAYClass : public CvNormalBayesClassifier{
  10 +public:
  11 + int get_nclasses(){
  12 + return CvNormalBayesClassifier::cls_labels->cols;
  13 + }
  14 +};
  15 +
  16 +/// Perform classification of the ENVI file using the current BAY classifier
  17 +std::vector< stim::image<unsigned char> > predict_bay(stim::envi* E, BAYClass* BAY, unsigned char* MASK = NULL){
  18 +
  19 + size_t nC = BAY->get_nclasses();
  20 + size_t X = E->header.samples;
  21 + size_t Y = E->header.lines;
  22 + size_t B = E->header.bands;
  23 + size_t XY = E->header.samples * E->header.lines;
  24 +
  25 + size_t tP = 0; //calculate the total number of pixels
  26 + if(MASK){
  27 + for(size_t xy = 0; xy < XY; xy++){
  28 + if(MASK[xy]) tP++;
  29 + }
  30 + }
  31 + else
  32 + tP = X * Y;
  33 +
  34 + std::vector< stim::image<unsigned char> > C; //create an array of mask images
  35 + C.resize(nC);
  36 +
  37 + for(unsigned long long c = 0; c < nC; c++){ //for each class mask
  38 + C[c] = stim::image<unsigned char>(X, Y, 1); //allocate space for the mask
  39 + C[c] = 0; //initialize all of the pixels to zero
  40 + }
  41 +
  42 + cv::Mat classF(1, (int)B, CV_32FC1); //allocate space for a single feature vector
  43 +
  44 +
  45 + //double progress = 0; //initialize the progress bar variable
  46 + std::thread t1(progressbar_thread, &progress); //start the progress bar thread
  47 +
  48 + unsigned long long t = 0;
  49 + for(unsigned long long p = 0; p < XY; p++){ //for each pixel
  50 + if(!MASK || MASK[p] > 0){
  51 + E->spectrum<float>((float*)classF.data, (int)p); //fill the classF matrix with a single spectrum
  52 + float c = BAY->predict(classF); //classify the feature vector
  53 + if((size_t)c < C.size()) //if the class returned is valid
  54 + C[(size_t)c].data()[p] = 255; //write a white pixel to the appropriate class image
  55 + t++;
  56 + progress = (double)(t+1) / (double)(tP) * 100.0; //update the progress bar variable
  57 + }
  58 + }
  59 + t1.join(); //finish the progress bar thread
  60 +
  61 + return C;
  62 +}
  63 +
  64 +//function for training a bayesian classifier
  65 +void train_bay(BAYClass* BAY, cv::Mat &trainF, cv::Mat &trainR, bool VERBOSE = false){
  66 +
  67 + unsigned tP = trainF.cols; //calculate the number of individual measurements
  68 +
  69 + if(VERBOSE) std::cout<<"Starting OpenCV CvBAY training algorithm...";
  70 + BAY->train(trainF, trainR); //train the classifier
  71 + if(VERBOSE) std::cout<<"done"<<std::endl;
  72 +}
0 73 \ No newline at end of file
... ...
src/class_gmm.h 0 โ†’ 100644
  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 +
... ...
src/class_kmeans.h 0 โ†’ 100644
  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 &centers, 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 +
... ...
src/class_rf.h 0 โ†’ 100644
  1 +++ a/src/class_rf.h
  1 +//OpenCV
  2 +#include <opencv2/opencv.hpp>
  3 +
  4 +#include "progress_thread.h"
  5 +
  6 +//create a custom classifier to access the number of classes (OpenCV protected variable)
  7 +class RFClass : public CvRTrees{
  8 +public:
  9 + int get_nclasses(){ return CvRTrees::nclasses;}
  10 +};
  11 +
  12 +/// Perform classification of the ENVI file using the current RF classifier
  13 +std::vector< stim::image<unsigned char> > predict_rf(stim::envi* E, RFClass* RF, unsigned char* MASK = NULL){
  14 +
  15 + size_t nC = RF->get_nclasses(); //get the number of classes
  16 + size_t X = E->header.samples;
  17 + size_t Y = E->header.lines;
  18 + size_t B = E->header.bands;
  19 + size_t XY = E->header.samples * E->header.lines;
  20 +
  21 + size_t tP = 0; //calculate the total number of pixels
  22 + if(MASK){
  23 + for(size_t xy = 0; xy < XY; xy++){
  24 + if(MASK[xy]) tP++;
  25 + }
  26 + }
  27 + else
  28 + tP = X * Y;
  29 +
  30 + std::vector< stim::image<unsigned char> > C; //create an array of mask images
  31 + C.resize(nC);
  32 +
  33 + for(unsigned long long c = 0; c < nC; c++){ //for each class mask
  34 + C[c] = stim::image<unsigned char>(X, Y, 1); //allocate space for the mask
  35 + memset(C[c].data(), 0, X * Y * sizeof(unsigned char)); //initialize all of the pixels to zero
  36 + }
  37 +
  38 + cv::Mat classF(1, (int)B, CV_32FC1); //allocate space for a single feature vector
  39 +
  40 +
  41 + double progress = 0; //initialize the progress bar variable
  42 + std::thread t1(progressbar_thread, &progress); //start the progress bar thread
  43 +
  44 + unsigned long long t = 0;
  45 + for(unsigned long long p = 0; p < XY; p++){ //for each pixel
  46 + if(!MASK || MASK[p] > 0){
  47 + E->spectrum<float>((float*)classF.data, (int)p); //fill the classF matrix with a single spectrum
  48 + float c = RF->predict(classF); //classify the feature vector
  49 + C[(size_t)c].data()[p] = 255; //write a white pixel to the appropriate class image
  50 + t++;
  51 + progress = (double)(t+1) / (double)(tP) * 100.0; //update the progress bar variable
  52 + }
  53 + }
  54 + t1.join(); //finish the progress bar thread
  55 +
  56 + return C;
  57 +}
  58 +
  59 +//function for training a random forest classifier
  60 +void train_rf(RFClass* RF, cv::Mat &trainF, cv::Mat &trainR, int tree_depth, int num_trees, bool VERBOSE = false){
  61 +
  62 + //unsigned tP = trainF.cols; //calculate the number of individual measurements
  63 +
  64 + CvRTParams params( tree_depth, // max_depth,
  65 + 1, // min_sample_count,
  66 + 0.f, // regression_accuracy,
  67 + false, // use_surrogates,
  68 + 16, // max_categories,
  69 + 0, // priors,
  70 + false, // calc_var_importance,
  71 + 0, // nactive_vars,
  72 + num_trees, // max_num_of_trees_in_the_forest,
  73 + 0, // forest_accuracy,
  74 + CV_TERMCRIT_ITER // termcrit_type
  75 + );
  76 +
  77 + if(VERBOSE) std::cout<<"Starting OpenCV CvRT training algorithm...";
  78 + RF->train(trainF, CV_ROW_SAMPLE, trainR, cv::Mat(), cv::Mat(), cv::Mat(), cv::Mat(), params ); //train the classifier
  79 + if(VERBOSE) std::cout<<"done"<<std::endl;
  80 +}
0 81 \ No newline at end of file
... ...
src/mask_manipulation.h 0 โ†’ 100644
  1 +++ a/src/mask_manipulation.h
  1 +#ifndef MASK_MANIPULATION
  2 +#define MASK_MANIPULATION
  3 +
  4 +#include <numeric>
  5 +
  6 +#include <stim/image/image.h>
  7 +
  8 +///This file contains functions designed to process, subsample, and manipulate masks images
  9 +
  10 +void push_training_image(std::vector< stim::image<unsigned char> >& C, std::vector<size_t>& nP, size_t& tP, stim::image<unsigned char> I) {
  11 + C.push_back(I);
  12 + size_t npixels = I.nnz();
  13 + nP.push_back(npixels); //push the number of pixels onto the pixel array
  14 + tP += npixels; //add to the running total of pixels
  15 +// nC++;
  16 +}
  17 +
  18 +//re-calculates the total number of pixels in an image list
  19 +size_t calc_tP(std::vector< stim::image<unsigned char> >& C, std::vector< size_t > nP) {
  20 + size_t tP = 0;
  21 + for (size_t i = 0; i < C.size(); i++) {
  22 + tP += nP[i];
  23 + }
  24 + return tP;
  25 +}
  26 +
  27 +size_t calc_tP(std::vector< stim::image<unsigned char> >& C) {
  28 + std::vector<size_t> nP(C.size());
  29 + for (size_t ci = 0; ci < C.size(); ci++)
  30 + nP[ci] = C[ci].nnz();
  31 + return calc_tP(C, nP);
  32 +}
  33 +
  34 +//load a mask given a mask filename
  35 +void AND_mask(std::vector< stim::image<unsigned char> >& C, std::vector<size_t>& nP, size_t& tP, std::string maskfile){
  36 + stim::image<unsigned char> mask_image(maskfile); //load the image
  37 + stim::image<unsigned char> mono_image = mask_image.channel(0); //retrieve the first channel
  38 +
  39 + if(C.size() == 0){
  40 + push_training_image(C, nP, tP, mono_image);
  41 + }
  42 + else{
  43 + size_t N = C[0].width() * C[0].height(); //precompute the number of pixels in the mask
  44 + tP = 0;
  45 + for(size_t xy = 0; xy < N; xy++){ //for each pixel in the mask
  46 + if(!C.back().data()[xy] || !mono_image.data()[xy]){ //if both the current and new mask is true
  47 + C.back().data()[xy] = 0;
  48 + }
  49 + }
  50 + nP.back() = C.back().nnz();
  51 + }
  52 + calc_tP(C, nP);
  53 + std::cout<<"masked pixels: "<<tP<<std::endl;
  54 +}
  55 +
  56 +void push_full_mask(std::vector< stim::image< unsigned char > >& C, size_t X, size_t Y) {
  57 + stim::image<unsigned char> img(X, Y, 1); //create an empty image
  58 + img = 255; //set all values to 255
  59 +
  60 + C.push_back(img); //push the image onto the image array
  61 +}
  62 +
  63 +void push_fully_masked_image(std::vector< stim::image< unsigned char > >& C, std::vector<size_t>& nP, size_t& tP, size_t X, size_t Y){
  64 +
  65 + push_full_mask(C, X, Y);
  66 +
  67 + size_t npixels = C[C.size() - 1].nnz();
  68 + nP.push_back(npixels); //push the number of pixels onto the pixel array
  69 + tP += npixels; //add to the running total of pixels
  70 + //nC++; //increment the number of classes
  71 +}
  72 +
  73 +void subsample_masks(std::vector< stim::image<unsigned char> >&I, size_t n) {
  74 + size_t tP = calc_tP(I);
  75 + if (tP <= n) return; //if there are less than n pixels already, nothing changes
  76 +
  77 + std::vector< stim::image<unsigned char> > new_C; //create a new training image array
  78 + new_C.resize(I.size()); //set the correct size of the array
  79 +
  80 + std::vector<size_t> idx(tP); //create an array that will store the indices of each pixel
  81 + size_t ip = 0; //index into the index array
  82 +
  83 + size_t X = I[0].width();
  84 + size_t Y = I[0].height();
  85 +
  86 + for (size_t c = 0; c < I.size(); c++) { //for each training image
  87 + new_C[c] = stim::image<unsigned char>(X, Y, 1); //create a new image that matches the size of the original
  88 + new_C[c] = 0; //set all values in the image to zero
  89 + std::vector<size_t> c_idx = I[c].sparse_idx(); //get the indices of each non-zero pixel
  90 +
  91 + for (size_t i = 0; i < c_idx.size(); i++) { //for each index
  92 + idx[ip + i] = c_idx[i] + c * X * Y; //scale the index by the image number and store it in the index array
  93 + }
  94 + ip += c_idx.size(); //increment the global index
  95 + }
  96 +
  97 + std::random_device rd; //create a random number generation function
  98 + std::mt19937 g(rd());
  99 + std::shuffle(idx.begin(), idx.end(), g); //shuffle the index values
  100 +
  101 + size_t c, ix;
  102 + for (size_t i = 0; i < n; i++) { //for each of the first n random pixels
  103 + c = idx[i] / (X * Y); //calculate the image that the current pixel is in
  104 + ix = idx[i] - c * X * Y; //calculate the 1D index of the current pixel
  105 + new_C[c].data()[ix] = I[c].data()[ix]; //store the value of the pixel in the new C array
  106 + }
  107 +
  108 + I = new_C; //replace the class image array
  109 +}
  110 +
  111 +/// This function picks a random set of N samples from among the training masks
  112 +void set_random_samples(std::vector< stim::image<unsigned char> >& C, std::vector<size_t>& nP, size_t& tP, size_t n){
  113 +
  114 + subsample_masks(C, n);
  115 +
  116 + tP = 0; //reset the total number of pixels to zero
  117 + for(size_t c = 0; c < C.size(); c++){ //for each class image
  118 + nP[c] = C[c].nnz(); //re-calculate the number of pixels in each image
  119 + tP += nP[c]; //re-calculate the total number of pixels
  120 + }
  121 +}
  122 +
  123 +/// Calculate a new image composed of N random pixels from the input image
  124 +stim::image<unsigned char> random_subset(stim::image<unsigned char> in, size_t n) {
  125 + if (n >= in.nnz()) return in; //if the number of pixels requested is less than the number of masked pixels, return the original image
  126 + std::vector<size_t> idx = in.sparse_idx(); //get the indices of each non-zero pixel
  127 + std::random_device rd; //create a random number generation function
  128 + std::mt19937 g(rd());
  129 + std::shuffle(idx.begin(), idx.end(), g); //shuffle the index values
  130 +
  131 + stim::image<unsigned char> out(in.width(), in.height(), 1); //create an output image the same size as the input image
  132 + out = 0; //set all pixels to zero
  133 +
  134 + for (size_t i = 0; i < n; i++) //go through each pixel index until the number of requested pixels is reached
  135 + out.data()[idx[i]] = 255; //set the pixel value at that location to TRUE
  136 +
  137 + return out; //return the output image
  138 +}
  139 +
  140 +
  141 +/// This function picks a random set of N samples from among the training masks. The samples are selected to make the training
  142 +/// set as balanced as possible (equal numbers of training samples from each class).
  143 +void set_random_samples_balanced(std::vector< stim::image< unsigned char > >& C, size_t n, std::string output_mask) {
  144 +
  145 + //size_t tP = calc_tP(C, nP);
  146 + //if (tP <= n) return; //if there are less than n pixels already, nothing changes
  147 +
  148 + std::vector< stim::image<unsigned char> > new_C; //create a new training image array
  149 + new_C.resize(C.size()); //set the correct size of the array
  150 +
  151 + //calculate the number of pixels in each training image
  152 + std::vector<size_t> num_pix_per_class(C.size()); //create a vector to store the number of pixels in each class
  153 + for (size_t c = 0; c < C.size(); c++) //for each class
  154 + num_pix_per_class[c] = C[c].nnz(); //calculate the number of pixels
  155 +
  156 + std::vector<int> c_idx(num_pix_per_class.size()); //create a vector that will store indices into the sorted class array
  157 + std::iota(c_idx.begin(), c_idx.end(), 0); //fill the index array with a list of indices [0, c)
  158 +
  159 + //create a function that compares two values in the num_pix_per_class array and sorts the indices
  160 + auto comparator = [&num_pix_per_class](int a, int b) { return num_pix_per_class[a] < num_pix_per_class[b]; };
  161 + std::sort(c_idx.begin(), c_idx.end(), comparator); //sort the indices, which can be used to look up the sorted version of the number of pixels per class
  162 +
  163 + size_t ppc = n / C.size(); //calculate the ideal number of pixels per class
  164 + size_t pixels_used = 0; //number of pixels that have already been accepted into the mask array
  165 +
  166 + for (size_t ci = 0; ci < C.size(); ci++) { //for each class (starting with the smallest)
  167 + ppc = (n - pixels_used) / (C.size() - ci); //determine the number of pixels per class that have to be used to balance out the rest of the classes
  168 + size_t pix = C[c_idx[ci]].nnz(); //get the number of pixels in this class
  169 + new_C[c_idx[ci]] = random_subset(C[c_idx[ci]], ppc); //get a random subset of the class
  170 + pixels_used += new_C[c_idx[ci]].nnz(); //get the actual number of pixels in the subsample and use it to increment the number of pixels used in the new mask images
  171 + }
  172 +
  173 + C = new_C; //replace the class image array
  174 +
  175 + if (output_mask != "") { //if the user specifies a mask filename, save each subsampled image
  176 + stim::filename fmask = output_mask; //create a file name object from the mask string
  177 + for (size_t c = 0; c < C.size(); c++) {
  178 + stim::filename f = fmask.insert(c, 4); //generate a numbered file name
  179 + C[c].save(f.str()); //convert the file name to a string and save the image
  180 + }
  181 + }
  182 +
  183 + /*//tP = 0; //reset the total number of pixels to zero
  184 + for (size_t c = 0; c < C.size(); c++) { //for each class image
  185 + //nP[c] = C[c].nnz(); //re-calculate the number of pixels in each image
  186 + //tP += nP[c]; //re-calculate the total number of pixels
  187 + if (maskfile != "") {
  188 + std::stringstream ss;
  189 + ss << "resample_class_" << c << ".bmp";
  190 + C[c].save(ss.str());
  191 + }
  192 + }*/
  193 +}
  194 +
  195 +
  196 +#endif
0 197 \ No newline at end of file
... ...
src/proc/bandimage.cpp 0 โ†’ 100644
  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 +}
... ...
src/proc/baseline.cpp 0 โ†’ 100644
  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 +}
... ...
src/proc/hsiproc.cpp 0 โ†’ 100644
  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 +}
... ...
src/proc/metric.cpp 0 โ†’ 100644
  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 +}
... ...
src/proc/mnf.cpp 0 โ†’ 100644
  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
... ...
src/proc/mosaic.cpp 0 โ†’ 100644
  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 +
... ...
src/proc/spero.cpp 0 โ†’ 100644
  1 +++ a/src/proc/spero.cpp
  1 +#include "stim/parser/filename.h"
  2 +#include "stim/envi/envi.h"
  3 +#include "stim/visualization/colormap.h"
  4 +
  5 +#include <thread>
  6 +#include <algorithm>
  7 +#include <unordered_map>
  8 +#include <fstream>
  9 +void progress_thread_double(double* e); //progress bar threaded function
  10 +
  11 +struct speroFile{
  12 + int x;
  13 + int y;
  14 + stim::filename headername;
  15 +};
  16 +
  17 +void spero_coord(int &x, int &y, stim::filename filename){
  18 +
  19 + //get the file prefix
  20 + std::string prefix = filename.get_prefix();
  21 +
  22 + //these files are in the format:
  23 + // ???????????[xxxxx_yyyyy][??????????].hdr
  24 +
  25 + //first find the x coordinate
  26 +
  27 + //find the position of the first bracket
  28 + size_t start = prefix.find_first_of("[") + 1; //find the first element of the y coordinate
  29 + prefix = prefix.substr(start, prefix.length() - start);
  30 + size_t end = prefix.find_first_of("_"); //find the index of the last element of the y coordinate
  31 +
  32 + std::string x_string = prefix.substr(0, end);
  33 +
  34 + x = atoi(x_string.c_str());
  35 +
  36 + //crop out the x coordinate and the last underscore
  37 + prefix = prefix.substr(end + 1, prefix.length() - end);
  38 + end = prefix.find_first_of("]");
  39 + std::string y_string = prefix.substr(0, end);
  40 +
  41 + y = atoi(y_string.c_str());
  42 + //find the y coordinate using the same method as above
  43 +/* size_t x_start = prefix.find_last_of("_");
  44 + std::string x_string = prefix.substr(x_start + 1);
  45 + x = atoi(x_string.c_str());*/
  46 +}
  47 +
  48 +void mosaic_spero(std::string directory, std::string outfile){
  49 +
  50 + std::cout<<"Building a mosaic from SPERO frames..."<<std::endl;
  51 +
  52 + //generate a list of dmd files
  53 + stim::filename f = directory + "/*.hdr";
  54 + std::vector<stim::filename> hdr_list = f.get_list();
  55 +
  56 + std::vector<speroFile> speroFiles; //create a list of spero files
  57 + speroFiles.resize(hdr_list.size()); //pre-allocate to save time (we know how many there are)
  58 + for(size_t i = 0; i < hdr_list.size(); i++){ //for each header name
  59 + spero_coord(speroFiles[i].x, speroFiles[i].y, hdr_list[i]);
  60 + speroFiles[i].headername = hdr_list[i].str();
  61 + //speroFiles[i].file.open(hdr_list[i].str_noext(), hdr_list[i].str());
  62 + //speroFiles[i].file.close(); //close the file (can only keep so many open at once)
  63 + }
  64 +
  65 + //calculate the height of the image by looking at how many files have the same x coordinate
  66 + size_t height = 0; //stores the width of the array
  67 + int first_x; //the first x value encountered
  68 + for(size_t i = 0; i < speroFiles.size(); i++){ //for each file
  69 + if(i == 0) first_x = speroFiles[i].x; //if this is the first file, store the x coordinate
  70 + else{ //otherwise
  71 + if(speroFiles[i].x != first_x){ //if the x-coord of this file is not the same as the first file
  72 + height = (int)i; //we now know the number of files
  73 + break; //exit the loop
  74 + }
  75 + }
  76 + }
  77 + size_t width = speroFiles.size() / height; //the number of files should be divisible by the width to get the height
  78 +
  79 +
  80 + std::vector<int> yvals(height); //stores the height values
  81 + for(size_t i = 0; i < height; i++) //go through the first "width" files and store their y values
  82 + yvals[i] = speroFiles[i].y;
  83 +
  84 + std::vector<int> xvals(width); //stores the width values
  85 + for(size_t i = 0; i < speroFiles.size(); i += height) //go through every "width" file and store the x coordinate
  86 + xvals[i/height] = speroFiles[i].x;
  87 +
  88 + std::sort(&yvals[0], &yvals[0] + yvals.size()); //sort both arrays of coordinates
  89 + std::sort(&xvals[0], &xvals[0] + xvals.size());
  90 +
  91 + //create a mapping from the x and y coordinates to their indices
  92 + std::unordered_map<int, size_t> x2idx;
  93 + std::unordered_map<int, size_t> y2idx;
  94 +
  95 + for(size_t i = 0; i < height; i++) y2idx.insert(std::pair<int, size_t>(yvals[i], i)); //unordered maps now give an index for a coordinate
  96 + for(size_t i = 0; i < width; i++) x2idx.insert(std::pair<int, size_t>(xvals[i], i));
  97 +
  98 + std::vector<stim::envi> M; //create an array of ENVI files in mosaic order
  99 + M.resize(speroFiles.size());
  100 +
  101 + size_t xi, yi;
  102 + for(size_t i = 0; i < M.size(); i++){ //for each input file
  103 + xi = x2idx[speroFiles[i].x]; //get the x and y indices for this file's position in the mosaic
  104 + yi = y2idx[speroFiles[i].y];
  105 +
  106 + M[yi * width + xi].open(speroFiles[i].headername.str_noext(), speroFiles[i].headername.str()); //open the ENVI file and set parameters
  107 + M[yi * width + xi].close(); //close the file, since we can only open so many
  108 + }
  109 +
  110 + std::ofstream target(outfile.c_str(), std::ios::binary); //create a file to store the output
  111 +
  112 + stim::envi_header h = M[0].header; //create a header for the mosaic
  113 + h.samples *= width;
  114 + h.lines *= height;
  115 + size_t tile_width = M[0].header.samples;
  116 + size_t tile_height = M[0].header.lines;
  117 +
  118 + //h.bands = 10;
  119 +
  120 + double progress = 0;
  121 + std::thread t1(progress_thread_double, &progress); //start the progress bar thread
  122 +
  123 + float* band = (float*) malloc(h.samples * h.lines * sizeof(float)); //allocate space for a band image
  124 + float* tile_band = (float*) malloc(tile_width * tile_height * sizeof(float));
  125 + size_t dst, src;
  126 + for(size_t b = 0; b < h.bands; b++){
  127 + for(size_t yi = 0; yi < height; yi++){
  128 + for(size_t xi = 0; xi < width; xi++){
  129 + M[yi * width + xi].open();
  130 + M[yi * width + xi].band_index(tile_band, b);
  131 + for(size_t y = 0; y < tile_height; y++){
  132 + dst = (yi * tile_height + tile_height - y - 1) * h.samples + xi * tile_width;
  133 + src = y * tile_width;
  134 + memcpy(band + dst, tile_band + src, sizeof(float) * tile_width);
  135 + }
  136 + //stim::cpu2image(tile_band, outfile + ".bmp", tile_width, tile_height, stim::cmBrewer);
  137 + //exit(1);
  138 + M[yi * width + xi].close();
  139 +
  140 + progress = (double)((b+1) * (yi+1) * (xi + 1)) / (width * height * h.bands) * 100;
  141 + }
  142 + }
  143 + target.write((char*)band, h.samples * h.lines * sizeof(float));
  144 + //stim::cpu2image(band, outfile + ".bmp", h.samples, h.lines, stim::cmBrewer);
  145 + //exit(1);
  146 + }
  147 +
  148 + t1.join(); //wait for the thread to terminate
  149 +
  150 + target.close(); //close the output file
  151 + h.save(outfile + ".hdr"); //write the header
  152 +
  153 + free(band);
  154 +}
0 155 \ No newline at end of file
... ...
src/progress_t.cpp 0 โ†’ 100644
  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 +}
... ...
src/progress_thread.h 0 โ†’ 100644
  1 +++ a/src/progress_thread.h
  1 +#ifndef PROGRESS_THREAD
  2 +#define PROGRESS_THREAD
  3 +
  4 +//function to display a progress bar
  5 +void progressbar_thread(double* e){
  6 +
  7 + unsigned int p = 0;
  8 + while(p != 100){
  9 + std::cout.flush();
  10 + if(*e > p){
  11 + p = (unsigned int)(*e);
  12 + rtsProgressBar(p);
  13 + }
  14 + }
  15 + std::cout<<std::endl; //put a newline after the completed progress bar
  16 +}
  17 +
  18 +#endif
0 19 \ No newline at end of file
... ...
src/spero/spero.cpp 0 โ†’ 100644
  1 +++ a/src/spero/spero.cpp
  1 +#include <iostream>
  2 +#include <algorithm>
  3 +#include <unordered_map>
  4 +#include <stim/parser/arguments.h>
  5 +#include <stim/envi/agilent_binary.h>
  6 +#include <stim/parser/filename.h>
  7 +#include <stim/envi/envi.h>
  8 +
  9 +stim::arglist args; //generate a list of accepted arguments
  10 +
  11 +#include <thread>
  12 +void progress_thread_double(double* e); //progress bar threaded function
  13 +
  14 +struct speroFile {
  15 + int x;
  16 + int y;
  17 + stim::filename headername;
  18 +};
  19 +
  20 +void spero_coord(int &x, int &y, stim::filename filename) {
  21 +
  22 + //get the file prefix
  23 + std::string prefix = filename.get_prefix();
  24 +
  25 + //these files are in the format:
  26 + // ???????????[xxxxx_yyyyy][??????????].hdr
  27 +
  28 + //first find the x coordinate
  29 +
  30 + //find the position of the first bracket
  31 + size_t start = prefix.find_first_of("[") + 1; //find the first element of the y coordinate
  32 + prefix = prefix.substr(start, prefix.length() - start);
  33 + size_t end = prefix.find_first_of("_"); //find the index of the last element of the y coordinate
  34 +
  35 + std::string x_string = prefix.substr(0, end);
  36 +
  37 + x = atoi(x_string.c_str());
  38 +
  39 + //crop out the x coordinate and the last underscore
  40 + prefix = prefix.substr(end + 1, prefix.length() - end);
  41 + end = prefix.find_first_of("]");
  42 + std::string y_string = prefix.substr(0, end);
  43 +
  44 + y = atoi(y_string.c_str());
  45 + //find the y coordinate using the same method as above
  46 + /* size_t x_start = prefix.find_last_of("_");
  47 + std::string x_string = prefix.substr(x_start + 1);
  48 + x = atoi(x_string.c_str());*/
  49 +}
  50 +
  51 +bool sperosort(speroFile i, speroFile j) {
  52 + return i.x < j.x;
  53 +}
  54 +
  55 +//This function test to make sure that the given file names are valid for a SPERO reconstruction
  56 +bool verify_filenames(std::vector<stim::filename> files) {
  57 + size_t idx = files[0].prefix().find('[');
  58 + if (idx == std::string::npos) return false;
  59 + for (size_t i = 0; i < files.size() - 1; i++) {
  60 + if (files[i].prefix().substr(0, idx) != files[i + 1].prefix().substr(0, idx)) return false;
  61 + }
  62 + return true;
  63 +}
  64 +
  65 +void mosaic_spero(std::string directory, std::string outfile) {
  66 +
  67 + //test for wild-cards in the directory
  68 + if (directory.find('*') != std::string::npos || directory.find('?') != std::string::npos) {
  69 + std::cout << "ERROR: no wild-cards are allowed, just specify the source directory containing SPERO files" << std::endl;
  70 + exit(1);
  71 + }
  72 +
  73 + std::cout << "Building a mosaic from SPERO frames..." << std::endl;
  74 +
  75 + //generate a list of dmd files
  76 + stim::filename f = directory + "/*.hdr";
  77 + std::vector<stim::filename> hdr_list = f.get_list();
  78 + if (hdr_list.size() == 0) {
  79 + std::cout << "ERROR: no files found for assembly" << std::endl;
  80 + exit(1);
  81 + }
  82 + std::cout << hdr_list.size() << " files found" << std::endl;
  83 +
  84 + if (!verify_filenames(hdr_list)) {
  85 + std::cout << "ERROR: incorrect file prefix found - all files should have the same prefix" << std::endl;
  86 + exit(1);
  87 + }
  88 +
  89 + if (hdr_list.size() == 0) {
  90 + std::cout << "ERROR: no header files found in directory '" + directory << std::endl;
  91 + exit(1);
  92 + }
  93 +
  94 + std::vector<speroFile> speroFiles; //create a list of spero files
  95 + speroFiles.resize(hdr_list.size()); //pre-allocate to save time (we know how many there are)
  96 + for (size_t i = 0; i < hdr_list.size(); i++) { //for each header name
  97 + spero_coord(speroFiles[i].x, speroFiles[i].y, hdr_list[i]);
  98 + speroFiles[i].headername = hdr_list[i].str();
  99 + }
  100 +
  101 + //sort the SPERO files by x coordinate
  102 + std::sort(speroFiles.begin(), speroFiles.end(), sperosort);
  103 +
  104 + //calculate the height of the image by looking at how many files have the same x coordinate
  105 + size_t height = 0; //stores the width of the array
  106 + int first_x; //the first x value encountered
  107 + for (size_t i = 0; i < speroFiles.size(); i++) { //for each file
  108 + if (i == 0) first_x = speroFiles[i].x; //if this is the first file, store the x coordinate
  109 + if (first_x == speroFiles[i].x) height++;
  110 + else break;
  111 + }
  112 + size_t width;
  113 + if (height == 0) width = speroFiles.size();
  114 + else width = speroFiles.size() / height; //the number of files should be divisible by the width to get the height
  115 +
  116 + if (width * height != speroFiles.size()) {
  117 + std::cout << "ERROR: calculated width and height do not match the number of input files: " << width << " x " << height << " = " << width * height << " found, " << speroFiles.size() << " needed" << std::endl;
  118 + exit(1);
  119 + }
  120 +
  121 + std::vector<int> yvals(height); //stores the height values
  122 + for (size_t i = 0; i < height; i++) //go through the first "width" files and store their y values
  123 + yvals[i] = speroFiles[i].y;
  124 +
  125 + std::vector<int> xvals(width); //stores the width values
  126 + for (size_t i = 0; i < speroFiles.size(); i += height) //go through every "width" file and store the x coordinate
  127 + xvals[i / height] = speroFiles[i].x;
  128 +
  129 + std::sort(&yvals[0], &yvals[0] + yvals.size()); //sort both arrays of coordinates
  130 + std::sort(&xvals[0], &xvals[0] + xvals.size());
  131 +
  132 + //create a mapping from the x and y coordinates to their indices
  133 + std::unordered_map<int, size_t> x2idx;
  134 + std::unordered_map<int, size_t> y2idx;
  135 +
  136 + for (size_t i = 0; i < height; i++) y2idx.insert(std::pair<int, size_t>(yvals[i], i)); //unordered maps now give an index for a coordinate
  137 + for (size_t i = 0; i < width; i++) x2idx.insert(std::pair<int, size_t>(xvals[i], i));
  138 +
  139 + std::vector<stim::envi> M; //create an array of ENVI files in mosaic order
  140 + M.resize(speroFiles.size());
  141 +
  142 + size_t xi, yi;
  143 + for (size_t i = 0; i < M.size(); i++) { //for each input file
  144 + xi = x2idx[speroFiles[i].x]; //get the x and y indices for this file's position in the mosaic
  145 + yi = y2idx[speroFiles[i].y];
  146 +
  147 + size_t idx = yi * width + xi;
  148 + M[idx].open(speroFiles[i].headername.str_noext(), speroFiles[i].headername.str()); //open the ENVI file and set parameters
  149 + M[idx].close(); //close the file, since we can only open so many
  150 + }
  151 +
  152 + std::ofstream target(outfile.c_str(), std::ios::binary); //create a file to store the output
  153 +
  154 + stim::envi_header h = M[0].header; //create a header for the mosaic
  155 + h.samples *= width;
  156 + h.lines *= height;
  157 + size_t tile_width = M[0].header.samples;
  158 + size_t tile_height = M[0].header.lines;
  159 +
  160 + double progress = 0;
  161 + std::thread t1(progress_thread_double, &progress); //start the progress bar thread
  162 +
  163 + float* band = (float*)malloc(h.samples * h.lines * sizeof(float)); //allocate space for a band image
  164 + float* tile_band = (float*)malloc(tile_width * tile_height * sizeof(float));
  165 + size_t dst, src;
  166 +
  167 + //reconstruct the array
  168 + for (size_t b = 0; b < h.bands; b++) { //for each band
  169 + for (size_t yi = 0; yi < height; yi++) { //for each tile in X and Y
  170 + for (size_t xi = 0; xi < width; xi++) {
  171 + M[yi * width + xi].open(); //open the tile
  172 + M[yi * width + xi].band_index(tile_band, b); //fill the tile_band pointer with the tile image at band b
  173 + for (size_t y = 0; y < tile_height; y++) { //copy the tile image to the destination band image
  174 + //dst = (yi * tile_height + tile_height - y - 1) * h.samples + xi * tile_width;
  175 + dst = ((height - yi - 1) * tile_height + y) * h.samples + xi * tile_width;
  176 + src = y * tile_width;
  177 + memcpy(band + dst, tile_band + src, sizeof(float) * tile_width);
  178 + }
  179 +
  180 + M[yi * width + xi].close(); //close the tile
  181 +
  182 + progress = (double)(b * height * width + yi * width + xi + 1) / (width * height * h.bands) * 100; //update the progress bar
  183 + }
  184 + }
  185 + target.write((char*)band, h.samples * h.lines * sizeof(float)); //write the entire band to the output image
  186 + }
  187 +
  188 + t1.join(); //wait for the thread to terminate
  189 +
  190 + target.close(); //close the output file
  191 + h.save(outfile + ".hdr"); //write the header
  192 +
  193 + free(band);
  194 +}
  195 +
  196 +void advertise() {
  197 + std::cout << std::endl << std::endl;
  198 + std::cout << "=========================================================================" << std::endl;
  199 + std::cout << "Thank you for using the SIPROC spectroscopic image processing toolkit!" << std::endl;
  200 + std::cout << "Scalable Tissue Imaging and Modeling (STIM) Lab, University of Houston" << std::endl;
  201 + std::cout << "Developers: Sam Saki, Ziqi He, David Mayerich, Brad Deutsch" << std::endl;
  202 + std::cout << "Source: https://github.com/stimlab/hsiproc.git" << std::endl;
  203 + std::cout << "This version has been compiled on " << __DATE__ << " at " << __TIME__ << std::endl;
  204 + std::cout << "=========================================================================" << std::endl << std::endl;
  205 +
  206 + std::cout << "Daylight SPERO mosaic assembly usage:" << std::endl;
  207 + std::cout << " >> spero directory/to/files mosaic" << std::endl;
  208 +}
  209 +
  210 +int main(int argc, char* argv[]) {
  211 +
  212 + args.add("help", "print help");
  213 + args.parse(argc, argv); //parse the argument list
  214 +
  215 + if (args["help"]) {
  216 + std::cout << args.str() << std::endl;
  217 + exit(1);
  218 + }
  219 + std::string indir = ".";
  220 + std::string outfile = "mosaic";
  221 + if (args.nargs() == 1) outfile = args.arg(0); //if only one argument is given, assume it is the output file
  222 + else if (args.nargs() >= 2) { //if two arguments are given
  223 + indir = args.arg(0); //the first argument is the directory
  224 + outfile = args.arg(1); //the second argument is the output file
  225 + }
  226 + std::cout << "SPERO mosaic assembly: " << indir << " --> " << outfile << std::endl;
  227 + mosaic_spero(indir, outfile); //call the SPERO mosaic function
  228 +}
0 229 \ No newline at end of file
... ...
src/view/hsiview.cpp 0 โ†’ 100644
  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 +}
... ...