From: schaerer Date: Wed, 6 Jan 2010 13:31:56 +0000 (+0000) Subject: Initial revision X-Git-Tag: v1.2.0~869 X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=commitdiff_plain;h=931a42358442f4ee4f314613c991c838d4b4e3b7;p=clitk.git Initial revision --- 931a42358442f4ee4f314613c991c838d4b4e3b7 diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000..6fc3a25 --- /dev/null +++ b/.cvsignore @@ -0,0 +1,14 @@ +CVS +tests_jef +mctools +*.swp +Makefile +tags +doc +CVS +CMakeFiles +CMakeCache.txt +*_ggo.* +*.directory +build/* +*/.vimrc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6fc3a25 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +CVS +tests_jef +mctools +*.swp +Makefile +tags +doc +CVS +CMakeFiles +CMakeCache.txt +*_ggo.* +*.directory +build/* +*/.vimrc diff --git a/.vimrc b/.vimrc new file mode 100644 index 0000000..4bdc3aa --- /dev/null +++ b/.vimrc @@ -0,0 +1,4 @@ +"clitk related standards +" +set makeprg=/home/jschaerer/workspace/cvs/clitk2-new/fast_make.sh +set grepprg=clgrep diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..8476152 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,80 @@ +#========================================================= +# CLITK = Command Line ITK +cmake_minimum_required(VERSION 2.4) +cmake_policy(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) +PROJECT(clitk) +#========================================================= +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") +#========================================================= +# Find ITK (required) +FIND_PACKAGE(ITK) +IF(ITK_FOUND) + INCLUDE(${ITK_USE_FILE}) + LINK_LIBRARIES(ITKBasicFilters) +ELSE(ITK_FOUND) + MESSAGE(FATAL_ERROR + "Cannot build without ITK. Please set ITK_DIR.") +ENDIF(ITK_FOUND) +#========================================================= +IF(CLITK_BUILD_VV) + FIND_PACKAGE(VTK) + IF(VTK_FOUND) + INCLUDE(${VTK_USE_FILE}) + LINK_LIBRARIES ( + vtkCommon + vtkRendering + vtkIO + vtkFiltering + vtkGraphics + vtkWidgets + vtkImaging + ) + ELSE(VTK_FOUND) + MESSAGE(FATAL_ERROR + "Please set VTK_DIR.") + ENDIF(VTK_FOUND) +ENDIF(CLITK_BUILD_VV) + +#========================================================= +# Find gengetopt +FIND_PATH(CLITK_GENGETOPT gengetopt) +IF (CLITK_GENGETOPT STREQUAL "CLITK_GENGETOPT-NOTFOUND") + MESSAGE("gengetopt not found, please install it (see http://www.gnu.org/software/gengetopt/gengetopt.html)") +ENDIF (CLITK_GENGETOPT STREQUAL "CLITK_GENGETOPT-NOTFOUND") +#========================================================= + +#========================================================= +INCLUDE(cmake/common.cmake) +#========================================================= + +#========================================================= +# Building in the source tree is forbidden +IF(PROJECT_BINARY_DIR STREQUAL ${PROJECT_SOURCE_DIR}) + MESSAGE(FATAL_ERROR "Building in the source tree is not allowed ! Quit; remove the file 'CMakeCache.txt' and the folder 'CMakeFiles' an +d build outside the sources (for example 'mkdir build ; cmake '.") +ENDIF(PROJECT_BINARY_DIR STREQUAL ${PROJECT_SOURCE_DIR}) +#========================================================= + +#========================================================= +OPTION(CLITK_BUILD_VV "Build vv the 4D visualizer (requires VTK and QT)" ON) +OPTION(CLITK_BUILD_TOOLS "Build command-line tools" OFF) +#========================================================= + +include_directories(itk filters) + +#========================================================= +add_subdirectory(common) +add_subdirectory(filters) + +IF (CLITK_BUILD_VV) + add_subdirectory(vv) +ENDIF(CLITK_BUILD_VV) + +IF (CLITK_BUILD_TOOLS) + add_subdirectory(tools) +ENDIF(CLITK_BUILD_TOOLS) + +#========================================================= diff --git a/clitk.doxygen b/clitk.doxygen new file mode 100644 index 0000000..c83ff98 --- /dev/null +++ b/clitk.doxygen @@ -0,0 +1,1294 @@ +# Doxyfile 1.5.3 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file that +# follow. The default is UTF-8 which is also the encoding used for all text before +# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into +# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of +# possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = CLITK + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, +# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, +# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, +# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to +# include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be extracted +# and appear in the documentation as a namespace called 'anonymous_namespace{file}', +# where file will be replaced with the base name of the file that contains the anonymous +# namespace. By default anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = common vv + +# This tag can be used to specify the character encoding of the source files that +# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default +# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. +# See http://www.gnu.org/software/libiconv for the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the output. +# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, +# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH +# then you must also enable this option. If you don't then doxygen will produce +# a warning and turn it on anyway + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to +# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to +# specify the directory where the mscgen tool resides. If left empty the tool is assumed to +# be found in the default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will +# generate a caller dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the number +# of direct children of the root node in a graph is already larger than +# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = YES diff --git a/cmake/FindROOT.cmake1 b/cmake/FindROOT.cmake1 new file mode 100644 index 0000000..4fdc250 --- /dev/null +++ b/cmake/FindROOT.cmake1 @@ -0,0 +1,229 @@ +# - Find ROOT instalation +# This module tries to find the ROOT installation on your system. +# It tries to find the root-config script which gives you all the needed information. +# If the system variable ROOTSYS is set this is straight forward. +# If not the module uses the pathes given in ROOT_CONFIG_SEARCHPATH. +# If you need an other path you should add this path to this varaible. +# The root-config script is then used to detect basically everything else. +# This module defines a number of key variables and macros. + + +MESSAGE("Looking for Root...") +MESSAGE(STATUS "Looking for Root...") + +SET(ROOT_CONFIG_SEARCHPATH + ${SIMPATH}/tools/root/bin + $ENV{ROOTSYS}/bin +) + +SET(ROOT_DEFINITIONS "") + +SET(ROOT_INSTALLED_VERSION_TOO_OLD FALSE) + +SET(ROOT_CONFIG_EXECUTABLE ROOT_CONFIG_EXECUTABLE-NOTFOUND) + +FIND_PROGRAM(ROOT_CONFIG_EXECUTABLE NAMES root-config PATHS + ${ROOT_CONFIG_SEARCHPATH} + NO_SYSTEM_ENVIRONMENT_PATH) + +IF (${ROOT_CONFIG_EXECUTABLE} MATCHES "ROOT_CONFIG_EXECUTABLE-NOTFOUND") + MESSAGE( FATAL_ERROR "ROOT not installed in the searchpath and ROOTSYS is not set. Please + set ROOTSYS or add the path to your ROOT installation in the Macro FindROOT.cmake in the + subdirectory cmake/modules.") +ELSE (${ROOT_CONFIG_EXECUTABLE} MATCHES "ROOT_CONFIG_EXECUTABLE-NOTFOUND") + MESSAGE("root-config found") + STRING(REGEX REPLACE "(^.*)/bin/root-config" "\\1" test ${ROOT_CONFIG_EXECUTABLE}) + SET( ENV{ROOTSYS} ${test}) + set( ROOTSYS ${test}) +ENDIF (${ROOT_CONFIG_EXECUTABLE} MATCHES "ROOT_CONFIG_EXECUTABLE-NOTFOUND") + + +IF (ROOT_CONFIG_EXECUTABLE) + + SET(ROOT_FOUND FALSE) + + EXEC_PROGRAM(${ROOT_CONFIG_EXECUTABLE} ARGS "--version" OUTPUT_VARIABLE ROOTVERSION) + + MESSAGE(STATUS "Looking for Root... - found $ENV{ROOTSYS}/bin/root") + MESSAGE(STATUS "Looking for Root... - version ${ROOTVERSION} ") + + MESSAGE( "Looking for Root... - found $ENV{ROOTSYS}/bin/root") + MESSAGE( "Looking for Root... - version ${ROOTVERSION} ") + + # we need at least version 5.00/00 + IF (NOT ROOT_MIN_VERSION) + SET(ROOT_MIN_VERSION "5.00/00") + ENDIF (NOT ROOT_MIN_VERSION) + + # now parse the parts of the user given version string into variables + STRING(REGEX REPLACE "^([0-9]+)\\.[0-9][0-9]+\\/[0-9][0-9]+" "\\1" req_root_major_vers "${ROOT_MIN_VERSION}") + STRING(REGEX REPLACE "^[0-9]+\\.([0-9][0-9])+\\/[0-9][0-9]+.*" "\\1" req_root_minor_vers "${ROOT_MIN_VERSION}") + STRING(REGEX REPLACE "^[0-9]+\\.[0-9][0-9]+\\/([0-9][0-9]+)" "\\1" req_root_patch_vers "${ROOT_MIN_VERSION}") + + # and now the version string given by qmake + STRING(REGEX REPLACE "^([0-9]+)\\.[0-9][0-9]+\\/[0-9][0-9]+.*" "\\1" found_root_major_vers "${ROOTVERSION}") + STRING(REGEX REPLACE "^[0-9]+\\.([0-9][0-9])+\\/[0-9][0-9]+.*" "\\1" found_root_minor_vers "${ROOTVERSION}") + STRING(REGEX REPLACE "^[0-9]+\\.[0-9][0-9]+\\/([0-9][0-9]+).*" "\\1" found_root_patch_vers "${ROOTVERSION}") + + IF (found_root_major_vers LESS 5) + MESSAGE( FATAL_ERROR "Invalid ROOT version \"${ROOTERSION}\", at least major version 4 is required, e.g. \"5.00/00\"") + ENDIF (found_root_major_vers LESS 5) + + # compute an overall version number which can be compared at once + MATH(EXPR req_vers "${req_root_major_vers}*10000 + ${req_root_minor_vers}*100 + ${req_root_patch_vers}") + MATH(EXPR found_vers "${found_root_major_vers}*10000 + ${found_root_minor_vers}*100 + ${found_root_patch_vers}") + + IF (found_vers LESS req_vers) + SET(ROOT_FOUND FALSE) + SET(ROOT_INSTALLED_VERSION_TOO_OLD TRUE) + ELSE (found_vers LESS req_vers) + SET(ROOT_FOUND TRUE) + ENDIF (found_vers LESS req_vers) + +ENDIF (ROOT_CONFIG_EXECUTABLE) + +MESSAGE("root found = "${ROOT_FOUND}) + +IF (ROOT_FOUND) + + # ask root-config for the library dir + # Set ROOT_LIBRARY_DIR + + EXEC_PROGRAM( ${ROOT_CONFIG_EXECUTABLE} + ARGS "--libdir" + OUTPUT_VARIABLE ROOT_LIBRARY_DIR_TMP ) + + IF(EXISTS "${ROOT_LIBRARY_DIR_TMP}") + SET(ROOT_LIBRARY_DIR ${ROOT_LIBRARY_DIR_TMP} ) + ELSE(EXISTS "${ROOT_LIBRARY_DIR_TMP}") + MESSAGE("Warning: ROOT_CONFIG_EXECUTABLE reported ${ROOT_LIBRARY_DIR_TMP} as library path,") + MESSAGE("Warning: but ${ROOT_LIBRARY_DIR_TMP} does NOT exist, ROOT must NOT be installed correctly.") + ENDIF(EXISTS "${ROOT_LIBRARY_DIR_TMP}") + + # ask root-config for the binary dir + EXEC_PROGRAM(${ROOT_CONFIG_EXECUTABLE} + ARGS "--bindir" + OUTPUT_VARIABLE root_bins ) + SET(ROOT_BINARY_DIR ${root_bins}) + + # ask root-config for the include dir + EXEC_PROGRAM( ${ROOT_CONFIG_EXECUTABLE} + ARGS "--incdir" + OUTPUT_VARIABLE root_headers ) + SET(ROOT_INCLUDE_DIR ${root_headers}) + # CACHE INTERNAL "") + + # ask root-config for the library varaibles + EXEC_PROGRAM( ${ROOT_CONFIG_EXECUTABLE} +# ARGS "--noldflags --noauxlibs --libs" + ARGS "--glibs" + OUTPUT_VARIABLE root_flags ) + +# STRING(REGEX MATCHALL "([^ ])+" root_libs_all ${root_flags}) +# STRING(REGEX MATCHALL "-L([^ ])+" root_library ${root_flags}) +# REMOVE_FROM_LIST(root_flags "${root_libs_all}" "${root_library}") + + SET(ROOT_LIBRARIES ${root_flags}) + + # Make variables changeble to the advanced user + MARK_AS_ADVANCED( ROOT_LIBRARY_DIR ROOT_INCLUDE_DIR ROOT_DEFINITIONS) + + # Set ROOT_INCLUDES + SET( ROOT_INCLUDES ${ROOT_INCLUDE_DIR}) + + SET(LD_LIBRARY_PATH ${LD_LIBRARY_PATH} ${ROOT_LIBRARY_DIR}) + + ####################################### + # + # Check the executables of ROOT + # ( rootcint ) + # + ####################################### + + FIND_PROGRAM(ROOT_CINT_EXECUTABLE + NAMES rootcint + PATHS ${ROOT_BINARY_DIR} + NO_DEFAULT_PATH + ) + +ENDIF (ROOT_FOUND) + + +MESSAGE("icici") + + ########################################### + # + # Macros for building ROOT dictionary + # + ########################################### + +MACRO (ROOT_GENERATE_DICTIONARY_OLD ) + + set(INFILES "") + + foreach (_current_FILE ${ARGN}) + + IF (${_current_FILE} MATCHES "^.*\\.h$") + IF (${_current_FILE} MATCHES "^.*Link.*$") + set(LINKDEF_FILE ${_current_FILE}) + ELSE (${_current_FILE} MATCHES "^.*Link.*$") + set(INFILES ${INFILES} ${_current_FILE}) + ENDIF (${_current_FILE} MATCHES "^.*Link.*$") + ELSE (${_current_FILE} MATCHES "^.*\\.h$") + IF (${_current_FILE} MATCHES "^.*\\.cxx$") + set(OUTFILE ${_current_FILE}) + ELSE (${_current_FILE} MATCHES "^.*\\.cxx$") + set(INCLUDE_DIRS ${INCLUDE_DIRS} -I${_current_FILE}) + ENDIF (${_current_FILE} MATCHES "^.*\\.cxx$") + ENDIF (${_current_FILE} MATCHES "^.*\\.h$") + + endforeach (_current_FILE ${ARGN}) + +# MESSAGE("INFILES: ${INFILES}") +# MESSAGE("OutFILE: ${OUTFILE}") +# MESSAGE("LINKDEF_FILE: ${LINKDEF_FILE}") +# MESSAGE("INCLUDE_DIRS: ${INCLUDE_DIRS}") + + STRING(REGEX REPLACE "(^.*).cxx" "\\1.h" bla "${OUTFILE}") +# MESSAGE("BLA: ${bla}") + SET (OUTFILES ${OUTFILE} ${bla}) + + ADD_CUSTOM_COMMAND(OUTPUT ${OUTFILES} + COMMAND ${ROOT_CINT_EXECUTABLE} + ARGS -f ${OUTFILE} -c -DHAVE_CONFIG_H ${INCLUDE_DIRS} ${INFILES} ${LINKDEF_FILE} DEPENDS ${INFILES}) + +# MESSAGE("ROOT_CINT_EXECUTABLE has created the dictionary ${OUTFILE}") + +ENDMACRO (ROOT_GENERATE_DICTIONARY_OLD) + + ########################################### + # + # Macros for building ROOT dictionary + # + ########################################### + +MACRO (ROOT_GENERATE_DICTIONARY INFILES LINKDEF_FILE OUTFILE INCLUDE_DIRS_IN) + + set(INCLUDE_DIRS) + + foreach (_current_FILE ${INCLUDE_DIRS_IN}) + set(INCLUDE_DIRS ${INCLUDE_DIRS} -I${_current_FILE}) + endforeach (_current_FILE ${INCLUDE_DIRS_IN}) + + +# MESSAGE("INFILES: ${INFILES}") +# MESSAGE("OutFILE: ${OUTFILE}") +# MESSAGE("LINKDEF_FILE: ${LINKDEF_FILE}") +# MESSAGE("INCLUDE_DIRS: ${INCLUDE_DIRS}") + + STRING(REGEX REPLACE "^(.*)\\.(.*)$" "\\1.h" bla "${OUTFILE}") +# MESSAGE("BLA: ${bla}") + SET (OUTFILES ${OUTFILE} ${bla}) + + ADD_CUSTOM_COMMAND(OUTPUT ${OUTFILES} + COMMAND ${ROOT_CINT_EXECUTABLE} + ARGS -f ${OUTFILE} -c -DHAVE_CONFIG_H ${INCLUDE_DIRS} ${INFILES} ${LINKDEF_FILE} DEPENDS ${INFILES}) + +ENDMACRO (ROOT_GENERATE_DICTIONARY) + +MESSAGE("la") \ No newline at end of file diff --git a/cmake/FindROOT.cmake2 b/cmake/FindROOT.cmake2 new file mode 100644 index 0000000..02b456a --- /dev/null +++ b/cmake/FindROOT.cmake2 @@ -0,0 +1,225 @@ +# - Find ROOT instalation # This module tries to find the ROOT installation on your system. +# It tries to find the root-config script which gives you all the needed information. +# If the system variable ROOTSYS is set this is straight forward. +# If not the module uses the pathes given in ROOT_CONFIG_SEARCHPATH. +# If you need an other path you should add this path to this varaible. +# The root-config script is then used to detect basically everything else. +# This module defines a number of key variables and macros. + + +MESSAGE(STATUS "Looking for Root...") + +SET(ROOT_CONFIG_SEARCHPATH + $ENV{ROOTSYS}/bin + ) + +SET(ROOT_DEFINITIONS "") + +SET(ROOT_INSTALLED_VERSION_TOO_OLD FALSE) + +SET(ROOT_CONFIG_EXECUTABLE ROOT_CONFIG_EXECUTABLE-NOTFOUND) + +FIND_PROGRAM(ROOT_CONFIG_EXECUTABLE NAMES root-config PATHS + ${ROOT_CONFIG_SEARCHPATH} + NO_SYSTEM_ENVIRONMENT_PATH) + +FIND_FILE( RVERSION_H NAMES RVersion.h PATHS $ENV{ROOTSYS}/include ) + +IF ( RVERSION_H ) + FILE( READ ${RVERSION_H} RVERS_CONTENT ) + STRING( REGEX MATCH "#define ROOT_RELEASE \"[^\n]+\"\n" _line "${RVERS_CONTENT}" ) + STRING( REGEX REPLACE "#define ROOT_RELEASE \"([^\n]+)\"\n" "\\1" _match "${_line}") + IF(_match) + SET( ROOTVERSION ${_match}) + ENDIF(_match) +ENDIF( RVERSION_H ) + + +IF (ROOTVERSION) + + SET(ROOT_FOUND FALSE) + + MESSAGE(STATUS "Looking for Root... - found $ENV{ROOTSYS}/bin/root") + MESSAGE(STATUS "Looking for Root... - version ${ROOTVERSION} ") + + # we need at least version 5.00/00 + IF (NOT ROOT_MIN_VERSION) + SET(ROOT_MIN_VERSION "5.00/00") + ENDIF (NOT ROOT_MIN_VERSION) + + # now parse the parts of the user given version string into variables + STRING(REGEX REPLACE "^([0-9]+)\\.[0-9][0-9]+\\/[0-9][0-9]+" "\\1" req_root_major_vers "${ROOT_MIN_VERSION}") + STRING(REGEX REPLACE "^[0-9]+\\.([0-9][0-9])+\\/[0-9][0-9]+.*" "\\1" req_root_minor_vers "${ROOT_MIN_VERSION}") + STRING(REGEX REPLACE "^[0-9]+\\.[0-9][0-9]+\\/([0-9][0-9]+)" "\\1" req_root_patch_vers "${ROOT_MIN_VERSION}") + + # and now the version string given by qmake + STRING(REGEX REPLACE "^([0-9]+)\\.[0-9][0-9]+\\/[0-9][0-9]+.*" "\\1" found_root_major_vers "${ROOTVERSION}") + STRING(REGEX REPLACE "^[0-9]+\\.([0-9][0-9])+\\/[0-9][0-9]+.*" "\\1" found_root_minor_vers "${ROOTVERSION}") + STRING(REGEX REPLACE "^[0-9]+\\.[0-9][0-9]+\\/([0-9][0-9]+).*" "\\1" found_root_patch_vers "${ROOTVERSION}") + + IF (found_root_major_vers LESS 5) + MESSAGE( FATAL_ERROR "Invalid ROOT version \"${ROOTERSION}\", at least major version 4 is required, e.g. \"5.00/00\"") + ENDIF (found_root_major_vers LESS 5) + + # compute an overall version number which can be compared at once + MATH(EXPR req_vers "${req_root_major_vers}*10000 + ${req_root_minor_vers}*100 + ${req_root_patch_vers}") + MATH(EXPR found_vers "${found_root_major_vers}*10000 + ${found_root_minor_vers}*100 + ${found_root_patch_vers}") + + IF (found_vers LESS req_vers) + SET(ROOT_FOUND FALSE) + SET(ROOT_INSTALLED_VERSION_TOO_OLD TRUE) + ELSE (found_vers LESS req_vers) + SET(ROOT_FOUND TRUE) + ENDIF (found_vers LESS req_vers) + +ENDIF (ROOTVERSION) + + +IF (ROOT_FOUND) + + # ask root-config for the library dir + # Set ROOT_LIBRARY_DIR + IF( WIN32 ) + SET( ROOT_LIBRARY_DIR $ENV{ROOTSYS}/lib ) + SET( ROOT_INCLUDE_DIR $ENV{ROOTSYS}/include ) + SET( ROOT_BINARY_DIR $ENV{ROOTSYS}/bin ) + + ELSE( WIN32 ) + + EXEC_PROGRAM( ${ROOT_CONFIG_EXECUTABLE} + ARGS "--libdir" + OUTPUT_VARIABLE ROOT_LIBRARY_DIR_TMP ) + + IF(EXISTS "${ROOT_LIBRARY_DIR_TMP}") + SET(ROOT_LIBRARY_DIR ${ROOT_LIBRARY_DIR_TMP} ) + ELSE(EXISTS "${ROOT_LIBRARY_DIR_TMP}") + MESSAGE("Warning: ROOT_CONFIG_EXECUTABLE reported ${ROOT_LIBRARY_DIR_TMP} as library path,") + MESSAGE("Warning: but ${ROOT_LIBRARY_DIR_TMP} does NOT exist, ROOT must NOT be installed correctly.") + ENDIF(EXISTS "${ROOT_LIBRARY_DIR_TMP}") + + # ask root-config for the binary dir + EXEC_PROGRAM(${ROOT_CONFIG_EXECUTABLE} + ARGS "--bindir" + OUTPUT_VARIABLE root_bins ) + SET(ROOT_BINARY_DIR ${root_bins}) + + # ask root-config for the include dir + EXEC_PROGRAM( ${ROOT_CONFIG_EXECUTABLE} + ARGS "--incdir" + OUTPUT_VARIABLE root_headers ) + SET(ROOT_INCLUDE_DIR ${root_headers}) + # CACHE INTERNAL "") + + # ask root-config for the library varaibles + EXEC_PROGRAM( ${ROOT_CONFIG_EXECUTABLE} + ARGS "--noldflags --noauxlibs --libs" + OUTPUT_VARIABLE root_flags ) + + # STRING(REGEX MATCHALL "([^ ])+" root_libs_all ${root_flags}) + # STRING(REGEX MATCHALL "-L([^ ])+" root_library ${root_flags}) + # REMOVE_FROM_LIST(root_flags "${root_libs_all}" "${root_library}") + + SET(ROOT_LIBRARIES ${root_flags}) + + ENDIF( WIN32 ) + + # Make variables changeble to the advanced user + MARK_AS_ADVANCED( ROOT_LIBRARY_DIR ROOT_INCLUDE_DIR ROOT_DEFINITIONS) + + # Set ROOT_INCLUDES + SET( ROOT_INCLUDES ${ROOT_INCLUDE_DIR}) + + SET(LD_LIBRARY_PATH ${LD_LIBRARY_PATH} ${ROOT_LIBRARY_DIR}) + + ####################################### + # + # Check the executables of ROOT + # ( rootcint ) + # + ####################################### + + FIND_PROGRAM(ROOT_CINT_EXECUTABLE + NAMES rootcint + PATHS ${ROOT_BINARY_DIR} + NO_DEFAULT_PATH + ) + +ENDIF (ROOT_FOUND) + + + +########################################### +# +# Macros for building ROOT dictionary +# +########################################### + +MACRO (ROOT_GENERATE_DICTIONARY_OLD ) + + set(INFILES "") + + foreach (_current_FILE ${ARGN}) + + IF (${_current_FILE} MATCHES "^.*\\.h$") + IF (${_current_FILE} MATCHES "^.*Link.*$") + set(LINKDEF_FILE ${_current_FILE}) + ELSE (${_current_FILE} MATCHES "^.*Link.*$") + set(INFILES ${INFILES} ${_current_FILE}) + ENDIF (${_current_FILE} MATCHES "^.*Link.*$") + ELSE (${_current_FILE} MATCHES "^.*\\.h$") + IF (${_current_FILE} MATCHES "^.*\\.cxx$") + set(OUTFILE ${_current_FILE}) + ELSE (${_current_FILE} MATCHES "^.*\\.cxx$") + set(INCLUDE_DIRS ${INCLUDE_DIRS} -I${_current_FILE}) + ENDIF (${_current_FILE} MATCHES "^.*\\.cxx$") + ENDIF (${_current_FILE} MATCHES "^.*\\.h$") + + endforeach (_current_FILE ${ARGN}) + + # MESSAGE("INFILES: ${INFILES}") + # MESSAGE("OutFILE: ${OUTFILE}") + # MESSAGE("LINKDEF_FILE: ${LINKDEF_FILE}") + # MESSAGE("INCLUDE_DIRS: ${INCLUDE_DIRS}") + + STRING(REGEX REPLACE "(^.*).cxx" "\\1.h" bla "${OUTFILE}") + # MESSAGE("BLA: ${bla}") + SET (OUTFILES ${OUTFILE} ${bla}) + + ADD_CUSTOM_COMMAND(OUTPUT ${OUTFILES} + COMMAND ${ROOT_CINT_EXECUTABLE} + ARGS -f ${OUTFILE} -c -DHAVE_CONFIG_H ${INCLUDE_DIRS} ${INFILES} ${LINKDEF_FILE} DEPENDS ${INFILES}) + + # MESSAGE("ROOT_CINT_EXECUTABLE has created the dictionary ${OUTFILE}") + +ENDMACRO (ROOT_GENERATE_DICTIONARY_OLD) + +########################################### +# +# Macros for building ROOT dictionary +# +########################################### + +MACRO (ROOT_GENERATE_DICTIONARY INFILES LINKDEF_FILE OUTFILE INCLUDE_DIRS_IN) + + set(INCLUDE_DIRS) + + foreach (_current_FILE ${INCLUDE_DIRS_IN}) + set(INCLUDE_DIRS ${INCLUDE_DIRS} -I${_current_FILE}) + endforeach (_current_FILE ${INCLUDE_DIRS_IN}) + + + # MESSAGE("INFILES: ${INFILES}") + # MESSAGE("OutFILE: ${OUTFILE}") + # MESSAGE("LINKDEF_FILE: ${LINKDEF_FILE}") + # MESSAGE("INCLUDE_DIRS: ${INCLUDE_DIRS}") + + STRING(REGEX REPLACE "^(.*)\\.(.*)$" "\\1.h" bla "${OUTFILE}") + # MESSAGE("BLA: ${bla}") + SET (OUTFILES ${OUTFILE} ${bla}) + + ADD_CUSTOM_COMMAND(OUTPUT ${OUTFILES} + COMMAND ${ROOT_CINT_EXECUTABLE} + ARGS -f ${OUTFILE} -c -DHAVE_CONFIG_H ${INCLUDE_DIRS} ${INFILES} ${LINKDEF_FILE} DEPENDS ${INFILES}) + +ENDMACRO (ROOT_GENERATE_DICTIONARY) + diff --git a/cmake/FindRoot.cmake b/cmake/FindRoot.cmake new file mode 100644 index 0000000..2e3d19e --- /dev/null +++ b/cmake/FindRoot.cmake @@ -0,0 +1,220 @@ +# - Find ROOT instalation +# This module tries to find the ROOT installation on your system. +# It tries to find the root-config script which gives you all the needed information. +# If the system variable ROOTSYS is set this is straight forward. +# If not the module uses the pathes given in ROOT_CONFIG_SEARCHPATH. +# If you need an other path you should add this path to this varaible. +# The root-config script is then used to detect basically everything else. +# This module defines a number of key variables and macros. + + +MESSAGE(STATUS "Looking for Root...") + +SET(ROOT_CONFIG_SEARCHPATH + ${SIMPATH}/tools/root/bin + $ENV{ROOTSYS}/bin +) + +SET(ROOT_DEFINITIONS "") + +SET(ROOT_INSTALLED_VERSION_TOO_OLD FALSE) + +SET(ROOT_CONFIG_EXECUTABLE ROOT_CONFIG_EXECUTABLE-NOTFOUND) + +FIND_PROGRAM(ROOT_CONFIG_EXECUTABLE NAMES root-config PATHS + ${ROOT_CONFIG_SEARCHPATH} + NO_SYSTEM_ENVIRONMENT_PATH) + +IF (${ROOT_CONFIG_EXECUTABLE} MATCHES "ROOT_CONFIG_EXECUTABLE-NOTFOUND") + MESSAGE( FATAL_ERROR "ROOT not installed in the searchpath and ROOTSYS is not set. Please + set ROOTSYS or add the path to your ROOT installation in the Macro FindROOT.cmake in the + subdirectory cmake/modules.") +ELSE (${ROOT_CONFIG_EXECUTABLE} MATCHES "ROOT_CONFIG_EXECUTABLE-NOTFOUND") + STRING(REGEX REPLACE "(^.*)/bin/root-config" "\\1" test ${ROOT_CONFIG_EXECUTABLE}) + SET( ENV{ROOTSYS} ${test}) + set( ROOTSYS ${test}) +ENDIF (${ROOT_CONFIG_EXECUTABLE} MATCHES "ROOT_CONFIG_EXECUTABLE-NOTFOUND") + + +IF (ROOT_CONFIG_EXECUTABLE) + + SET(ROOT_FOUND FALSE) + + EXEC_PROGRAM(${ROOT_CONFIG_EXECUTABLE} ARGS "--version" OUTPUT_VARIABLE ROOTVERSION) + + MESSAGE(STATUS "Looking for Root... - found $ENV{ROOTSYS}/bin/root") + MESSAGE(STATUS "Looking for Root... - version ${ROOTVERSION} ") + + # we need at least version 5.00/00 + IF (NOT ROOT_MIN_VERSION) + SET(ROOT_MIN_VERSION "5.00/00") + ENDIF (NOT ROOT_MIN_VERSION) + + # now parse the parts of the user given version string into variables + STRING(REGEX REPLACE "^([0-9]+)\\.[0-9][0-9]+\\/[0-9][0-9]+" "\\1" req_root_major_vers "${ROOT_MIN_VERSION}") + STRING(REGEX REPLACE "^[0-9]+\\.([0-9][0-9])+\\/[0-9][0-9]+.*" "\\1" req_root_minor_vers "${ROOT_MIN_VERSION}") + STRING(REGEX REPLACE "^[0-9]+\\.[0-9][0-9]+\\/([0-9][0-9]+)" "\\1" req_root_patch_vers "${ROOT_MIN_VERSION}") + + # and now the version string given by qmake + STRING(REGEX REPLACE "^([0-9]+)\\.[0-9][0-9]+\\/[0-9][0-9]+.*" "\\1" found_root_major_vers "${ROOTVERSION}") + STRING(REGEX REPLACE "^[0-9]+\\.([0-9][0-9])+\\/[0-9][0-9]+.*" "\\1" found_root_minor_vers "${ROOTVERSION}") + STRING(REGEX REPLACE "^[0-9]+\\.[0-9][0-9]+\\/([0-9][0-9]+).*" "\\1" found_root_patch_vers "${ROOTVERSION}") + + IF (found_root_major_vers LESS 5) + MESSAGE( FATAL_ERROR "Invalid ROOT version \"${ROOTERSION}\", at least major version 4 is required, e.g. \"5.00/00\"") + ENDIF (found_root_major_vers LESS 5) + + # compute an overall version number which can be compared at once + MATH(EXPR req_vers "${req_root_major_vers}*10000 + ${req_root_minor_vers}*100 + ${req_root_patch_vers}") + MATH(EXPR found_vers "${found_root_major_vers}*10000 + ${found_root_minor_vers}*100 + ${found_root_patch_vers}") + + IF (found_vers LESS req_vers) + SET(ROOT_FOUND FALSE) + SET(ROOT_INSTALLED_VERSION_TOO_OLD TRUE) + ELSE (found_vers LESS req_vers) + SET(ROOT_FOUND TRUE) + ENDIF (found_vers LESS req_vers) + +ENDIF (ROOT_CONFIG_EXECUTABLE) + + +IF (ROOT_FOUND) + + # ask root-config for the library dir + # Set ROOT_LIBRARY_DIR + + EXEC_PROGRAM( ${ROOT_CONFIG_EXECUTABLE} + ARGS "--libdir" + OUTPUT_VARIABLE ROOT_LIBRARY_DIR_TMP ) + + IF(EXISTS "${ROOT_LIBRARY_DIR_TMP}") + SET(ROOT_LIBRARY_DIR ${ROOT_LIBRARY_DIR_TMP} ) + ELSE(EXISTS "${ROOT_LIBRARY_DIR_TMP}") + MESSAGE("Warning: ROOT_CONFIG_EXECUTABLE reported ${ROOT_LIBRARY_DIR_TMP} as library path,") + MESSAGE("Warning: but ${ROOT_LIBRARY_DIR_TMP} does NOT exist, ROOT must NOT be installed correctly.") + ENDIF(EXISTS "${ROOT_LIBRARY_DIR_TMP}") + + # ask root-config for the binary dir + EXEC_PROGRAM(${ROOT_CONFIG_EXECUTABLE} + ARGS "--bindir" + OUTPUT_VARIABLE root_bins ) + SET(ROOT_BINARY_DIR ${root_bins}) + + # ask root-config for the include dir + EXEC_PROGRAM( ${ROOT_CONFIG_EXECUTABLE} + ARGS "--incdir" + OUTPUT_VARIABLE root_headers ) + SET(ROOT_INCLUDE_DIR ${root_headers}) + # CACHE INTERNAL "") + + # ask root-config for the library varaibles + EXEC_PROGRAM( ${ROOT_CONFIG_EXECUTABLE} +# ARGS "--noldflags --noauxlibs --libs" + ARGS "--glibs" + OUTPUT_VARIABLE root_flags ) + +# STRING(REGEX MATCHALL "([^ ])+" root_libs_all ${root_flags}) +# STRING(REGEX MATCHALL "-L([^ ])+" root_library ${root_flags}) +# REMOVE_FROM_LIST(root_flags "${root_libs_all}" "${root_library}") + + SET(ROOT_LIBRARIES ${root_flags}) + + # Make variables changeble to the advanced user + MARK_AS_ADVANCED( ROOT_LIBRARY_DIR ROOT_INCLUDE_DIR ROOT_DEFINITIONS) + + # Set ROOT_INCLUDES + SET( ROOT_INCLUDES ${ROOT_INCLUDE_DIR}) + + SET(LD_LIBRARY_PATH ${LD_LIBRARY_PATH} ${ROOT_LIBRARY_DIR}) + + ####################################### + # + # Check the executables of ROOT + # ( rootcint ) + # + ####################################### + + FIND_PROGRAM(ROOT_CINT_EXECUTABLE + NAMES rootcint + PATHS ${ROOT_BINARY_DIR} + NO_DEFAULT_PATH + ) + +ENDIF (ROOT_FOUND) + + + + ########################################### + # + # Macros for building ROOT dictionary + # + ########################################### + +MACRO (ROOT_GENERATE_DICTIONARY_OLD ) + + set(INFILES "") + + foreach (_current_FILE ${ARGN}) + + IF (${_current_FILE} MATCHES "^.*\\.h$") + IF (${_current_FILE} MATCHES "^.*Link.*$") + set(LINKDEF_FILE ${_current_FILE}) + ELSE (${_current_FILE} MATCHES "^.*Link.*$") + set(INFILES ${INFILES} ${_current_FILE}) + ENDIF (${_current_FILE} MATCHES "^.*Link.*$") + ELSE (${_current_FILE} MATCHES "^.*\\.h$") + IF (${_current_FILE} MATCHES "^.*\\.cxx$") + set(OUTFILE ${_current_FILE}) + ELSE (${_current_FILE} MATCHES "^.*\\.cxx$") + set(INCLUDE_DIRS ${INCLUDE_DIRS} -I${_current_FILE}) + ENDIF (${_current_FILE} MATCHES "^.*\\.cxx$") + ENDIF (${_current_FILE} MATCHES "^.*\\.h$") + + endforeach (_current_FILE ${ARGN}) + +# MESSAGE("INFILES: ${INFILES}") +# MESSAGE("OutFILE: ${OUTFILE}") +# MESSAGE("LINKDEF_FILE: ${LINKDEF_FILE}") +# MESSAGE("INCLUDE_DIRS: ${INCLUDE_DIRS}") + + STRING(REGEX REPLACE "(^.*).cxx" "\\1.h" bla "${OUTFILE}") +# MESSAGE("BLA: ${bla}") + SET (OUTFILES ${OUTFILE} ${bla}) + + ADD_CUSTOM_COMMAND(OUTPUT ${OUTFILES} + COMMAND ${ROOT_CINT_EXECUTABLE} + ARGS -f ${OUTFILE} -c -DHAVE_CONFIG_H ${INCLUDE_DIRS} ${INFILES} ${LINKDEF_FILE} DEPENDS ${INFILES}) + +# MESSAGE("ROOT_CINT_EXECUTABLE has created the dictionary ${OUTFILE}") + +ENDMACRO (ROOT_GENERATE_DICTIONARY_OLD) + + ########################################### + # + # Macros for building ROOT dictionary + # + ########################################### + +MACRO (ROOT_GENERATE_DICTIONARY INFILES LINKDEF_FILE OUTFILE INCLUDE_DIRS_IN) + + set(INCLUDE_DIRS) + + foreach (_current_FILE ${INCLUDE_DIRS_IN}) + set(INCLUDE_DIRS ${INCLUDE_DIRS} -I${_current_FILE}) + endforeach (_current_FILE ${INCLUDE_DIRS_IN}) + + +# MESSAGE("INFILES: ${INFILES}") +# MESSAGE("OutFILE: ${OUTFILE}") +# MESSAGE("LINKDEF_FILE: ${LINKDEF_FILE}") +# MESSAGE("INCLUDE_DIRS: ${INCLUDE_DIRS}") + + STRING(REGEX REPLACE "^(.*)\\.(.*)$" "\\1.h" bla "${OUTFILE}") +# MESSAGE("BLA: ${bla}") + SET (OUTFILES ${OUTFILE} ${bla}) + + ADD_CUSTOM_COMMAND(OUTPUT ${OUTFILES} + COMMAND ${ROOT_CINT_EXECUTABLE} + ARGS -f ${OUTFILE} -c -DHAVE_CONFIG_H ${INCLUDE_DIRS} ${INFILES} ${LINKDEF_FILE} DEPENDS ${INFILES}) + +ENDMACRO (ROOT_GENERATE_DICTIONARY) diff --git a/cmake/common.cmake b/cmake/common.cmake new file mode 100644 index 0000000..d2496d0 --- /dev/null +++ b/cmake/common.cmake @@ -0,0 +1,51 @@ +#========================================================= +# Find ggo (gengetopt) files (http://www.gnu.org/software/gengetopt/) +FILE(GLOB ALL_GGO_FILES *.ggo) +#MESSAGE(${ALL_GGO_FILES}) + +FOREACH(GGO_FILE ${ALL_GGO_FILES}) + # MESSAGE(input=${GGO_FILE}) + STRING(REGEX REPLACE "(.*).ggo" + "\\1" GGO_BASEFILENAME + "${GGO_FILE}") + #GET_FILENAME_COMPONENT(GGO_BASEFILENAME ${GGO_FILE} NAME_WE) + GET_FILENAME_COMPONENT(GGO_NAME ${GGO_BASEFILENAME} NAME) + # MESSAGE( base= ${GGO_BASEFILENAME}) + # MESSAGE( name= ${GGO_NAME}) + SET(GGO_H ${GGO_BASEFILENAME}_ggo.h) + #MESSAGE(${GGO_H}) + SET(GGO_C ${GGO_BASEFILENAME}_ggo.c) + #MESSAGE(${GGO_C}) + SET(GGO_OUTPUT ${GGO_H} ${GGO_C}) + ADD_CUSTOM_COMMAND(OUTPUT ${GGO_OUTPUT} + COMMAND gengetopt + ARGS < ${GGO_FILE} --arg-struct-name=gengetopt_args_info_${GGO_NAME} --file-name=${GGO_BASEFILENAME}_ggo -u --conf-parser + DEPENDS ${GGO_FILE} + ) + ENDFOREACH(GGO_FILE) + +#========================================================= +#Set a reasonable build mode default if the user hasn't set any +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE RelWithDebInfo) +endif (NOT CMAKE_BUILD_TYPE) + +#========================================================= +SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin/) +SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) +LINK_DIRECTORIES(${PROJECT_BINARY_DIR}/lib) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ilr/base) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ilr/grid) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ilr/gridtools) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ilr/signal) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ilr/pose) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ilr/shearwarp) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ilr/synergy) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ilr/reconstruction) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ilr/register) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ilr/deformableregistration) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ilr/optim) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/common) +#INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/tests) +#INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/tools) +#========================================================= diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt new file mode 100644 index 0000000..a51a929 --- /dev/null +++ b/common/CMakeLists.txt @@ -0,0 +1,50 @@ +#========================================================= +# Compiled Image types +# Comment/uncomment desired image types + +#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIMAGETYPE_CHAR") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIMAGETYPE_UCHAR") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIMAGETYPE_SHORT") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIMAGETYPE_USHORT") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIMAGETYPE_INT") +#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIMAGETYPE_UINT") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIMAGETYPE_FLOAT") +#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIMAGETYPE_DOUBLE") + +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${ITK_DIR}/gdcm/src/") + +#========================================================= +# Compiled Image Dimension +# Comment/uncomment desired image dimensions + +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIMAGEDIM_1") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIMAGEDIM_2") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIMAGEDIM_3") +#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIMAGEDIM_4") + +#========================================================= +INCLUDE(${PROJECT_SOURCE_DIR}/cmake/common.cmake) +#========================================================= + +#========================================================= +# make clitk libraries + +SET(clitkCommon_SRC + clitkCommon.cxx + clitkListOfPair.cxx + clitkTimer.cxx + clitkImageCommon.cxx + clitkVoxImageIO.cxx + clitkVoxImageIOFactory.cxx + clitkVfImageIO.cxx + clitkVfImageIOFactory.cxx + clitkOrientation.cxx + clitkSignal.cxx + vvImage.cxx + clitkImageToImageGenericFilter.cxx + ) + +ADD_LIBRARY(clitkCommon STATIC ${clitkCommon_SRC}) + +#ADD_LIBRARY(clitkCommonShared SHARED ${clitkCommon_SRC}) +#SET_TARGET_PROPERTIES(clitkCommonShared PROPERTIES COMPILE_FLAGS -fPIC) diff --git a/common/clitkCommon.cxx b/common/clitkCommon.cxx new file mode 100644 index 0000000..d7ca47a --- /dev/null +++ b/common/clitkCommon.cxx @@ -0,0 +1,317 @@ +/*------------------------------------------------------------------------- + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +-------------------------------------------------------------------------*/ + +#ifndef CLITKCOMMON_CXX +#define CLITKCOMMON_CXX + +/** + ------------------------------------------------- + * @file clitkCommon.cxx + * @author David Sarrut + * @date 17 May 2006 07:59:06 + * + * @brief + * + * + -------------------------------------------------*/ + +#include "clitkCommon.h" +#include "itkMacro.h" + +//------------------------------------------------------------------ +// skip line which begin with a sharp '#' +void clitk::skipComment(std::istream & is) +{ + char c; + char line[1024]; + if (is.eof()) return; + is >> c ; + while (is && (c == '#')) { + is.getline (line, 1024); + is >> c; + if (is.eof()) return; + } + is.unget(); +} //// +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +// linear (rough) conversion from Hounsfield Unit to density +double clitk::HU2density(double HU) +{ + return (HU+1000.0)/1000.0; +} //// +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +// Return filename extension +std::string clitk::GetExtension(const std::string& filename) +{ + // This assumes that the final '.' in a file name is the delimiter + // for the file's extension type + const std::string::size_type it = filename.find_last_of( "." ); + // This determines the file's type by creating a new string + // who's value is the extension of the input filename + // eg. "myimage.gif" has an extension of "gif" + std::string fileExt( filename, it+1, filename.length() ); + return( fileExt ); +} //// +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +// Display progression +void clitk::VerboseInProgress(const int nb, const int current, const int percentage) +{ +int stage = current; + int number_of_stages = nb; + + static int exp = -1; + int prec = 4; + int p = (int)(stage*pow(10.0,prec)*1./number_of_stages); + if (p==exp) return; + exp = p; + float s = p * 100. / pow(10.0,prec); + char fmt[128]; + sprintf(fmt,"%%%i.%if%%%%",prec<4?prec:prec+1,prec>3?prec-3:0); + char ch[128]; + + snprintf(ch,2,fmt,s); + //sxsVSCU_MESSAGE(2,ch); + std::cout << ch << std::flush; + for (int i=0;i<(prec>3?prec+2:prec+1);++i) + std::cout << "\b" << std::flush;//sxsVSCU_MESSAGE(2,"\b"); + + /* + + if ((current % (nb/percentage)) == 0) { + std::cout.width(15); + std::cout << "\r" << current << "/" << nb << std::flush; + } + */ +} +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +// Display progression +void clitk::VerboseInProgressInPercentage(const int nb, const int current, const int percentage) +{ + int stage = current; + int number_of_stages = nb; + + static int exp = -1; + int prec = 4; + int p = (int)(stage*pow(10.0,prec)*1./number_of_stages); + if (p==exp) return; + exp = p; + float s = p * 100. / pow(10.0,prec); + char fmt[128]; + sprintf(fmt,"%%%i.%if%%%%",prec<4?prec:prec+1,prec>3?prec-3:0); + char ch[128]; + + snprintf(ch,2,fmt,s); + //sxsVSCU_MESSAGE(2,ch); + std::cout << ch << std::flush; + for (int i=0;i<(prec>3?prec+2:prec+1);++i) + std::cout << "\b" << std::flush;//sxsVSCU_MESSAGE(2,"\b"); + + /* + if (nb/percentage != 0) { + if ((current % (nb/percentage)) == 0) { + std::cout.width(2); + std::cout << "\r" << (nb/current)*100 << "/100% " << std::flush; + } + } + */ +} +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +// Convert a pixel type to another (downcast) +template<> +float clitk::PixelTypeDownCast(const double & x) +{ + return (float)x; +} +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +double clitk::rad2deg(const double anglerad) { + return (anglerad/M_PI*180.0); +} +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +double clitk::deg2rad(const double angledeg) { + return (angledeg*(M_PI/180.0)); +} +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +int clitk::GetTypeSizeFromString(const std::string & type) { +#define RETURN_SIZEOF_PIXEL(TYPENAME, TYPE) \ + if (type == #TYPENAME) return sizeof(TYPE); + RETURN_SIZEOF_PIXEL(char, char); + RETURN_SIZEOF_PIXEL(uchar, uchar); + RETURN_SIZEOF_PIXEL(unsigned char, uchar); + RETURN_SIZEOF_PIXEL(unsigned_char, uchar); + RETURN_SIZEOF_PIXEL(short, short); + RETURN_SIZEOF_PIXEL(ushort, ushort); + RETURN_SIZEOF_PIXEL(unsigned_short, ushort); + RETURN_SIZEOF_PIXEL(int, int); + RETURN_SIZEOF_PIXEL(uint, uint); + RETURN_SIZEOF_PIXEL(unsigned_int, uint); + RETURN_SIZEOF_PIXEL(float, float); + RETURN_SIZEOF_PIXEL(double, double); + return 0; +} +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +template<> +bool clitk::IsSameType(std::string t) { + if ((t==GetTypeAsString()) || (t == "schar")) return true; else return false; +} + +template<> +bool clitk::IsSameType(std::string t) { + if ((t==GetTypeAsString()) || (t == "char")) return true; else return false; +} + +template<> +bool clitk::IsSameType(std::string t) { + if ((t==GetTypeAsString()) || (t == "uchar")) return true; else return false; +} + +template<> +bool clitk::IsSameType(std::string t) { + if ((t==GetTypeAsString()) || (t == "ushort")) return true; else return false; +} +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +void clitk::FindAndReplace(std::string & line, + const std::string & tofind, + const std::string & replacement) { + int pos = line.find(tofind); + while (pos!= (int)std::string::npos) { + line.replace(pos, tofind.size(), replacement); + pos = line.find(tofind, pos+tofind.size()+1); + } +} +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +void clitk::FindAndReplace(std::string & line, + const std::vector & tofind, + const std::vector & toreplace) { + for(unsigned int i=0; i & tofind, + const std::vector & toreplace, + std::ofstream & out) { + std::string line; + if (tofind.size() != toreplace.size()) { + std::cerr << "Error' tofind' is size=" << tofind.size() << std::endl; + std::cerr << "... while 'toreplace' is size=" << toreplace.size() << std::endl; + exit(0); + } + while (std::getline(in,line)) { + FindAndReplace(line, tofind, toreplace); + out << line << std::endl; + } +} +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +double clitk::ComputeEuclideanDistanceFromPointToPlane(const itk::ContinuousIndex point, + const itk::ContinuousIndex pointInPlane, + const itk::ContinuousIndex normalPlane) { + // http://mathworld.wolfram.com/Plane.html + // http://mathworld.wolfram.com/Point-PlaneDistance.html + double a = normalPlane[0]; + double b = normalPlane[1]; + double c = normalPlane[2]; + double x0 = pointInPlane[0]; + double y0 = pointInPlane[1]; + double z0 = pointInPlane[2]; + double x = point[0]; + double y = point[1]; + double z = point[2]; + + double norm = sqrt(x0*x0 + y0*y0 + z0*z0); + DD(norm); + double d = -a*x0 - b*y0 - c*z0; + DD(d); + double distance = (a*x + b*y + c*z + d) / norm; + + return distance; +} +//------------------------------------------------------------------ + +//-------------------------------------------------------------------- +// Open a file for reading +void clitk::openFileForReading(std::ifstream & is, const std::string & filename) { + is.open(filename.c_str(), std::ios::in); + if ( is.fail() ) { + itkGenericExceptionMacro(<< "Could not open file (for reading): " << filename); + } +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +// Open a file for writing +void clitk::openFileForWriting(std::ofstream & os, const std::string & filename) { + os.open(filename.c_str(), std::ios::out); + if ( os.fail() ) { + itkGenericExceptionMacro(<< "Could not open file (for writing): " << filename); + } +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +double clitk::cotan(double i) { return(1.0 / tan(i)); } +double clitk::invcotan(double x) { + // http://mathworld.wolfram.com/InverseCotangent.html + double y; + if (x<0) { + y = -0.5*M_PI-atan(x); + } + else { + y = 0.5*M_PI-atan(x); + } + return y; +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +std::streambuf * clitk_stdcerr_backup; +void clitk::disableStdCerr() { + clitk_stdcerr_backup = std::cerr.rdbuf(); + std::stringstream oss; + std::cerr.rdbuf( oss.rdbuf() ); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::enableStdCerr() { + std::cerr.rdbuf(clitk_stdcerr_backup); +} +//-------------------------------------------------------------------- + +#endif /* end #define CLITKCOMMON_CXX */ + diff --git a/common/clitkCommon.h b/common/clitkCommon.h new file mode 100644 index 0000000..1c5f9a0 --- /dev/null +++ b/common/clitkCommon.h @@ -0,0 +1,203 @@ +#ifndef CLITKCOMMON_H +#define CLITKCOMMON_H + +/** + ------------------------------------------------------------------- + * @file clitkCommon.h + * @author David Sarrut + * @date 17 May 2006 07:57:56 + + * @brief + + -------------------------------------------------------------------*/ + +// std include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "itkMacro.h" +#include + +//-------------------------------------------------------------------- +namespace clitk { + +#if defined(WIN32) +#define lrint(x) (floor(x+(x>0) ? 0.5 : -0.5)) +#endif + + typedef unsigned char uchar; + typedef unsigned short ushort; + typedef unsigned int uint; + + //-------------------------------------------------------------------- + // display +#define DD(a) std::cout << #a " = [ " << a << " ]" << std::endl; +#define DDV(a,n) { std::cout << #a " = [ "; for(unsigned int _i_=0; _i_ std::string toString(const T & t); + template std::string toStringVector(const T * t, const int n); + template std::string toStringVector(const T & t, const int n); + template std::string toStringVector(const std::vector & t); + + //-------------------------------------------------------------------- + // Display a progress % + void VerboseInProgress(const int nb, const int current, const int percentage); + void VerboseInProgressInPercentage(const int nb, const int current, const int percentage); + + //-------------------------------------------------------------------- + // Convert a pixel type to another (downcast) + template + TPixelDown PixelTypeDownCast(const TPixelUp & x); + template<> + float PixelTypeDownCast(const double & x); + + //-------------------------------------------------------------------- + // Return the indexes of sorted values in a vector + template struct vectorComparisonLowerThan; + template struct vectorComparisonGreaterThan; + template + void GetSortedIndex(const std::vector & toSort, std::vector & index, bool increasing=true); + + //-------------------------------------------------------------------- + // Return the name of a type as a string + template + std::string GetTypeAsString(); + + //-------------------------------------------------------------------- + // Convert radian / degree + double rad2deg(double anglerad); + double deg2rad(double anglerad); + + //-------------------------------------------------------------------- + int GetTypeSizeFromString(const std::string & type); + + //-------------------------------------------------------------------- + // Special case to handle "signed_char = schar" ... + template + bool IsSameType(std::string t) { return (t==GetTypeAsString()); } + template<> bool IsSameType(std::string t); + template<> bool IsSameType(std::string t); + template<> bool IsSameType(std::string t); + template<> bool IsSameType(std::string t); + + //-------------------------------------------------------------------- + template + std::string CreateListOfTypes(bool last=true) { + return GetTypeAsString(); + } + + template + std::string CreateListOfTypes(bool last=true) { + if (last) return CreateListOfTypes()+" and "+CreateListOfTypes(); + else return CreateListOfTypes()+", "+CreateListOfTypes(); + } + + template + std::string CreateListOfTypes(bool last=true) { + if (last) return CreateListOfTypes(false)+" and "+CreateListOfTypes(); + else return CreateListOfTypes(false)+", "+CreateListOfTypes(); + } + + template + std::string CreateListOfTypes(bool last=true) { + if (last) return CreateListOfTypes(false)+" and "+CreateListOfTypes(); + else return CreateListOfTypes(false)+", "+CreateListOfTypes(); + } + + template + std::string CreateListOfTypes(bool last=true) { + if (last) return CreateListOfTypes(false)+" and "+CreateListOfTypes(); + else return CreateListOfTypes(false)+", "+CreateListOfTypes(); + } + + template + std::string CreateListOfTypes(bool last=true) { + if (last) return CreateListOfTypes(false)+" and "+CreateListOfTypes(); + else return CreateListOfTypes(false)+", "+CreateListOfTypes(); + } + + template + std::string CreateListOfTypes(bool last=true) { + if (last) return CreateListOfTypes(false)+" and "+CreateListOfTypes(); + else return CreateListOfTypes(false)+", "+CreateListOfTypes(); + } + + template + std::string CreateListOfTypes(bool last=true) { + if (last) return CreateListOfTypes(false)+" and "+CreateListOfTypes(); + else return CreateListOfTypes(false)+", "+CreateListOfTypes(); + } + //-------------------------------------------------------------------- + + //-------------------------------------------------------------------- + void FindAndReplace(std::string & line, const std::string & tofind, const std::string & replacement); + void FindAndReplace(std::string & line, const std::vector & tofind, const std::vector & toreplace); + void FindAndReplace(std::ifstream & in, const std::vector & tofind, const std::vector & toreplace, std::ofstream & out); + //-------------------------------------------------------------------- + + //-------------------------------------------------------------------- + double ComputeEuclideanDistanceFromPointToPlane(const itk::ContinuousIndex point, + const itk::ContinuousIndex pointInPlane, + const itk::ContinuousIndex normalPlane); + + //-------------------------------------------------------------------- + // Open a File for reading/writing + void openFileForReading(std::ifstream & is, const std::string & filename); + void openFileForWriting(std::ofstream & os, const std::string & filename); + + //-------------------------------------------------------------------- + double cotan(double i); + double invcotan(double i); + + //-------------------------------------------------------------------- + void disableStdCerr(); + void enableStdCerr(); + +#include "clitkCommon.txx" + +} // end namespace + +#endif /* end #define CLITKCOMMON_H */ + diff --git a/common/clitkCommon.txx b/common/clitkCommon.txx new file mode 100644 index 0000000..984ef76 --- /dev/null +++ b/common/clitkCommon.txx @@ -0,0 +1,132 @@ +/*------------------------------------------------------------------------- + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + -------------------------------------------------------------------------*/ + +#ifndef CLITKCOMMON_TXX +#define CLITKCOMMON_TXX + +/** + ------------------------------------------------- + * @file clitkCommon.txx + * @author David Sarrut + * @date 18 May 2006 + * + -------------------------------------------------*/ + +//-------------------------------------------------------------------- +// Convert float, double ... to string +template +std::string toString(const T & t) { + std::ostringstream myStream; + myStream << t << std::flush; + return(myStream.str()); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +// Convert float*, double* ... to string +template +std::string toStringVector(const T * t, const int n) { + std::ostringstream myStream; + for(int i=0; i(t[i]) << " "; + myStream << clitk::toString(t[n-1]) << std::flush; + return(myStream.str()); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +// Convert float*, double* ... to string +template +std::string toStringVector(const T & t, const int n) { + std::ostringstream myStream; + for(int i=0; i +std::string toStringVector(const std::vector & t) { + return toStringVector(&t[0], t.size()); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +// Convert a pixel type to another (downcast) +template +TPixelDown PixelTypeDownCast(const TPixelUp & x) { + return (TPixelDown)lrint(x); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +struct vectorComparisonLowerThan: public std::binary_function { + vectorComparisonLowerThan(const std::vector & v):vect(v) {}; + bool operator()(int x, int y) { + return (vect[x] < vect[y]); + } + const std::vector & vect; +}; +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +struct vectorComparisonGreaterThan: public std::binary_function { + vectorComparisonGreaterThan(const std::vector & v):vect(v) {}; + bool operator()(int x, int y) { + return (vect[x] > vect[y]); + } + const std::vector & vect; +}; +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +void GetSortedIndex(const std::vector & toSort, std::vector & index, bool increasing) { + index.resize(toSort.size()); + for(unsigned int i=0; i(toSort)); + else + std::sort(index.begin(), + index.end(), + vectorComparisonGreaterThan(toSort)); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +std::string GetTypeAsString() { + const std::type_info & PixType = typeid(TPixel); + std::string pixelName; + if (PixType == typeid(char)) pixelName = "char"; // 'plain" char is different from signed char and unsigned char ... + else if (PixType == typeid(signed char)) pixelName = "signed_char"; + else if (PixType == typeid(unsigned char)) pixelName = "unsigned_char"; + else if (PixType == typeid(short)) pixelName = "short"; + else if (PixType == typeid(unsigned short)) pixelName = "unsigned_short"; + else if (PixType == typeid(int)) pixelName = "int"; + else if (PixType == typeid(unsigned int)) pixelName = "unsigned_int"; + else if (PixType == typeid(float)) pixelName = "float"; + else if (PixType == typeid(double)) pixelName = "double"; + else pixelName = PixType.name(); + return pixelName; +} +//-------------------------------------------------------------------- + +#endif /* end #define CLITKCOMMON_TXX */ + diff --git a/common/clitkIO.h b/common/clitkIO.h new file mode 100644 index 0000000..cabf00e --- /dev/null +++ b/common/clitkIO.h @@ -0,0 +1,34 @@ +#ifndef CLITKIO_H +#define CLITKIO_H + +/** + ------------------------------------------------------------------- + * @file clitkIO.h + * @author David Sarrut + * @date 17 May 2006 07:57:56 + + * @brief + + -------------------------------------------------------------------*/ + +// std include +#include +#include + +// clitk include +#include "clitkCommon.h" +#include "clitkImageCommon.h" +#include "clitkVoxImageIO.h" +#include "clitkVoxImageIOFactory.h" +#include "clitkVfImageIO.h" +#include "clitkVfImageIOFactory.h" + +//-------------------------------------------------------------------- +// CLITK_INIT +#define CLITK_INIT \ + itk::ImageIOFactory::RegisterBuiltInFactories(); \ + clitk::VoxImageIOFactory::RegisterOneFactory(); \ + clitk::VfImageIOFactory::RegisterOneFactory(); + +#endif /* end #define CLITKIO_H */ + diff --git a/common/clitkIOCommon.cxx b/common/clitkIOCommon.cxx new file mode 100644 index 0000000..7344cb0 --- /dev/null +++ b/common/clitkIOCommon.cxx @@ -0,0 +1,160 @@ +/*========================================================================= + +Program: clitk +Module: $RCSfile: clitkIOCommon.cxx,v $ +Language: C++ +Date: $Date: 2010/01/06 13:32:01 $ +Version: $Revision: 1.1 $ + +Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de +l'Image). All rights reserved. See Doc/License.txt or +http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef CLITKIOCOMMON_CXX +#define CLITKIOCOMMON_CXX + +/** + ================================================= + * @file clitkIOCommon.cxx + * @author David Sarrut + * @date 18 May 2006 11:42:37 + * + * @brief + * + * + =================================================*/ + +// clitk include +#include "clitkIOCommon.h" + +//==================================================================== +// Open a file for reading +void clitk::openFileForReading(std::ifstream & is, const std::string & filename) { + is.open(filename.c_str(), std::ios::in); + if ( is.fail() ) { + itkGenericExceptionMacro(<< "Could not open file (for reading): " << filename); + } +} +//==================================================================== + +//==================================================================== +// Open a file for writing +void clitk::openFileForWriting(std::ofstream & os, const std::string & filename) { + os.open(filename.c_str(), std::ios::out); + if ( os.fail() ) { + itkGenericExceptionMacro(<< "Could not open file (for writing): " << filename); + } +} +//==================================================================== + +//==================================================================== +// Read a dicom header +gdcm::File * clitk::readDicomHeader(const std::string & filename, + const bool verbose) { + if (verbose) { + std::cout << "Reading DICOM <" << filename << ">" << std::endl; + } + gdcm::File *header = new gdcm::File(); + header->SetFileName(filename); + header->SetMaxSizeLoadEntry(16384); // required ? + header->Load(); + return header; +} +//==================================================================== + +//==================================================================== +itk::ImageIOBase::Pointer clitk::readImageHeader(const std::string & filename) { + itk::ImageIOBase::Pointer reader = + itk::ImageIOFactory::CreateImageIO(filename.c_str(), itk::ImageIOFactory::ReadMode); + if (!reader) return NULL; + reader->SetFileName(filename); + reader->ReadImageInformation(); + return reader; +} +//==================================================================== + +//==================================================================== +void clitk::printImageHeader(itk::ImageIOBase::Pointer header, std::ostream & os, const int level) { + unsigned int dim = header->GetNumberOfDimensions(); + std::string pixelTypeName = header->GetComponentTypeAsString(header->GetComponentType()); + std::vector inputSize; + std::vector inputSpacing; + inputSize.resize(dim); + inputSpacing.resize(dim); + for(unsigned int i=0; iGetSpacing(i); + inputSize[i] = header->GetDimensions(i); + } + int pixelSize = + clitk::GetTypeSizeFromString(header->GetComponentTypeAsString(header->GetComponentType())); + unsigned int nbOfComponents = header->GetNumberOfComponents(); + if (level == 0) { + os << dim << "D "; + if (nbOfComponents !=1) os << nbOfComponents << "x" << pixelTypeName; + else os << pixelTypeName; + os << " "; + for(unsigned int i=0; i< dim-1; i++) + os << inputSize[i] << "x"; + os << inputSize[dim-1] + << " "; + for(unsigned int i=0; i< dim-1; i++) + os << inputSpacing[i] << "x"; + os << inputSpacing[dim-1]; + } + else { + os << "Dim = " << dim << "D" << std::endl; + os << "PixelType = " << pixelTypeName << std::endl; + if (nbOfComponents > 1) + os << "Vector = " << nbOfComponents << std::endl; + os << "Size = "; + for(unsigned int i=0; i< dim; i++) { + os << inputSize[i] << " "; + } + os << std::endl; + os << "Spacing = "; + for(unsigned int i=0; i< dim; i++) { + os << inputSpacing[i] << " "; + } + os << std::endl; + if (level > 1) { + os << "# voxels = " << header->GetImageSizeInPixels() << std::endl; + os << "Size (mm) = "; + for(unsigned int i=0; i< dim; i++) { + os << inputSize[i]*inputSpacing[i] << " "; + } + os << "mm" << std::endl; + os << "Volume = "; + double vol=1.0; + for(unsigned int i=0; i< dim; i++) { + vol *= inputSize[i]*inputSpacing[i]/10.0; + } + os << vol << " cc" << std::endl; + int mem = header->GetImageSizeInPixels()*pixelSize*nbOfComponents; + double memKb = (double)mem/1024.0; + double memMb = (double)mem/1024.0/1024.0; + double memGb = (double)mem/1024.0/1024.0/1024.0; + if (lrint(memKb) <= 0) + os << "Memory = " << mem << " bytes" << std::endl; + else { + if (lrint(memMb) <= 0) + os << "Memory = " << memKb << " Kb (" << mem << " bytes)" << std::endl; + else { + if (lrint(memGb) <= 0) + os << "Memory = " << memMb << " Mb (" << mem << " bytes)" << std::endl; + else + os << "Memory = " << memGb << " Gb (" << mem << " bytes)" << std::endl; + } + } + } + } +} +//==================================================================== + +#endif /* end #define CLITKIO_CXX */ + diff --git a/common/clitkIOCommon.h b/common/clitkIOCommon.h new file mode 100644 index 0000000..69717a6 --- /dev/null +++ b/common/clitkIOCommon.h @@ -0,0 +1,3 @@ + +#include "clitkImageCommon.h" + diff --git a/common/clitkIOCommon.txx b/common/clitkIOCommon.txx new file mode 100644 index 0000000..65ad771 --- /dev/null +++ b/common/clitkIOCommon.txx @@ -0,0 +1,86 @@ +#ifndef CLITKIOCOMMON_TXX +#define CLITKIOCOMMON_TXX + +/** + ================================================= + * @file clitkIOCommon.txx + * @author David Sarrut + * @date 04 Jul 2006 08:34:11 + * + * @brief + * + * + =================================================*/ + +//==================================================================== +// To short the code for reading an image +template +typename ImageType::Pointer readImage(const std::string & filename, const bool verbose) { + typedef itk::ImageFileReader ReaderType; + typename ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(filename.c_str()); + if (verbose) { + std::cout << "Reading " << filename << " ..." << std::endl; + } + try { + reader->Update(); + } + catch( itk::ExceptionObject & err ) { + std::cerr << "Error while reading " << filename + << " " << err << std::endl; + exit(0); + } + return reader->GetOutput(); +} +//==================================================================== + +//==================================================================== +// To short the code for reading an image from several files +template +typename ImageType::Pointer readImage(const std::vector & filenames, + const bool verbose) { + if (filenames.size() == 1) return readImage(filenames[0], verbose); + typedef itk::ImageSeriesReader ReaderType; + typename ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileNames(filenames); + if (verbose) { + std::cout << "Reading " << filenames[0] << " and others ..." << std::endl; + } + try { + reader->Update(); + } + catch( itk::ExceptionObject & err ) { + std::cerr << "Error while reading " << filenames[0] + << " or other files ..." << err << std::endl; + exit(0); + } + return reader->GetOutput(); +} +//==================================================================== + +//==================================================================== +// To short the code for writing an image +template +void writeImage(const typename ImageType::Pointer image, + const std::string & filename, + const bool verbose) { + typedef itk::ImageFileWriter WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(filename.c_str()); + writer->SetInput(image); + if (verbose) { + std::cout << "Writing " << filename << "." << std::endl; + } + try { + writer->Update(); + } + catch( itk::ExceptionObject & err ) { + std::cerr << "Error while writing " << filename + << ", the error is : " << err << std::endl; + exit(0); + } +} +//==================================================================== + +#endif /* end #define CLITKIOCOMMON_TXX */ + diff --git a/common/clitkImageCommon.cxx b/common/clitkImageCommon.cxx new file mode 100644 index 0000000..056df94 --- /dev/null +++ b/common/clitkImageCommon.cxx @@ -0,0 +1,178 @@ +/*------------------------------------------------------------------------= + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + ------------------------------------------------------------------------=*/ + +#ifndef CLITKIMAGECOMMON_CXX +#define CLITKIMAGECOMMON_CXX + +/** + ------------------------------------------------= + * @file clitkImageCommon.cxx + * @author David Sarrut + * @date 02 Oct 2007 14:30:47 + * + * @brief + * + * + ------------------------------------------------=*/ + +#include "clitkImageCommon.h" + +//-------------------------------------------------------------------- +void clitk::ReadImageDimensionAndPixelType(const std::string & filename, + int & dimension, + std::string & pixeType) { + itk::ImageIOBase::Pointer genericReader = + itk::ImageIOFactory::CreateImageIO(filename.c_str(), itk::ImageIOFactory::ReadMode); + if (!genericReader) { + std::cerr << "Image file format unknown while reading " << filename << std::endl; + exit(0); + } + genericReader->SetFileName(filename.c_str()); + genericReader->ReadImageInformation(); + pixeType = genericReader->GetComponentTypeAsString(genericReader->GetComponentType()); + dimension = genericReader->GetNumberOfDimensions(); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +void clitk::ReadImageDimensionAndPixelType(const std::string & filename, + int & dimension, + std::string & pixeType, int & components) { + itk::ImageIOBase::Pointer genericReader = + itk::ImageIOFactory::CreateImageIO(filename.c_str(), itk::ImageIOFactory::ReadMode); + if (!genericReader) { + std::cerr << "Image file format unknown while reading " << filename << std::endl; + exit(0); + } + genericReader->SetFileName(filename.c_str()); + genericReader->ReadImageInformation(); + pixeType = genericReader->GetComponentTypeAsString(genericReader->GetComponentType()); + dimension = genericReader->GetNumberOfDimensions(); + components= genericReader->GetNumberOfComponents(); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +// Read a dicom header +gdcm::File * clitk::readDicomHeader(const std::string & filename, + const bool verbose) { + if (verbose) { + std::cout << "Reading DICOM <" << filename << ">" << std::endl; + } + gdcm::File *header = new gdcm::File(); + header->SetFileName(filename); + header->SetMaxSizeLoadEntry(16384); // required ? + header->Load(); + return header; +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +itk::ImageIOBase::Pointer clitk::readImageHeader(const std::string & filename) { + itk::ImageIOBase::Pointer reader = + itk::ImageIOFactory::CreateImageIO(filename.c_str(), itk::ImageIOFactory::ReadMode); + if (!reader) return NULL; + reader->SetFileName(filename); + reader->ReadImageInformation(); + return reader; +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::printImageHeader(itk::ImageIOBase::Pointer header, std::ostream & os, const int level) { + unsigned int dim = header->GetNumberOfDimensions(); + std::string pixelTypeName = header->GetComponentTypeAsString(header->GetComponentType()); + std::vector inputSize; + std::vector inputSpacing; + std::vector inputOrigin; + inputSize.resize(dim); + inputSpacing.resize(dim); + inputOrigin.resize(dim); + for(unsigned int i=0; iGetSpacing(i); + inputSize[i] = header->GetDimensions(i); + inputOrigin[i] = header->GetOrigin(i); + } + int pixelSize = + clitk::GetTypeSizeFromString(header->GetComponentTypeAsString(header->GetComponentType())); + unsigned int nbOfComponents = header->GetNumberOfComponents(); + if (level == 0) { + os << dim << "D "; + if (nbOfComponents !=1) os << nbOfComponents << "x" << pixelTypeName; + else os << pixelTypeName; + os << " "; + for(unsigned int i=0; i< dim-1; i++) + os << inputSize[i] << "x"; + os << inputSize[dim-1] + << " "; + for(unsigned int i=0; i< dim-1; i++) + os << inputSpacing[i] << "x"; + os << inputSpacing[dim-1]; + } + else { + os << "Dim = " << dim << "D" << std::endl; + os << "PixelType = " << pixelTypeName << std::endl; + if (nbOfComponents > 1) + os << "Vector = " << nbOfComponents << std::endl; + os << "Size = "; + for(unsigned int i=0; i< dim; i++) { + os << inputSize[i] << " "; + } + os << std::endl; + os << "Spacing = "; + for(unsigned int i=0; i< dim; i++) { + os << inputSpacing[i] << " "; + } + os << std::endl; + if (level > 1) { + os << "# voxels = " << header->GetImageSizeInPixels() << std::endl; + os << "Size (mm) = "; + for(unsigned int i=0; i< dim; i++) { + os << inputSize[i]*inputSpacing[i] << " "; + } + os << "mm" << std::endl; + os << "Origin (mm)= "; + for(unsigned int i=0; i< dim; i++) { + os << inputOrigin[i] << " "; + } + os << "mm" << std::endl; + + os << "Volume = "; + double vol=1.0; + for(unsigned int i=0; i< dim; i++) { + vol *= inputSize[i]*inputSpacing[i]/10.0; + } + os << vol << " cc" << std::endl; + int mem = header->GetImageSizeInPixels()*pixelSize*nbOfComponents; + double memKb = (double)mem/1024.0; + double memMb = (double)mem/1024.0/1024.0; + double memGb = (double)mem/1024.0/1024.0/1024.0; + if (lrint(memKb) <= 0) + os << "Memory = " << mem << " bytes" << std::endl; + else { + if (lrint(memMb) <= 0) + os << "Memory = " << memKb << " Kb (" << mem << " bytes)" << std::endl; + else { + if (lrint(memGb) <= 0) + os << "Memory = " << memMb << " Mb (" << mem << " bytes)" << std::endl; + else + os << "Memory = " << memGb << " Gb (" << mem << " bytes)" << std::endl; + } + } + } + } +} +//-------------------------------------------------------------------- + +#endif /* end #define CLITKIMAGECOMMON_CXX */ + diff --git a/common/clitkImageCommon.h b/common/clitkImageCommon.h new file mode 100644 index 0000000..53e1be6 --- /dev/null +++ b/common/clitkImageCommon.h @@ -0,0 +1,90 @@ +#ifndef CLITKIMAGECOMMON_H +#define CLITKIMAGECOMMON_H + +/** + ------------------------------------------------------------------- + * @file clitkImageCommon.h + * @author David Sarrut + * @date 07 Sep 2007 11:30:10 + + * @brief + + -------------------------------------------------------------------*/ + +// clitk +#include "clitkCommon.h" + +// itk +#include "itkImage.h" +#include "itkImageFileReader.h" +#include "itkImageSeriesReader.h" +#include "itkImageFileWriter.h" +#include "gdcmFile.h" +#include "gdcmFileHelper.h" + + +namespace clitk { + + //-------------------------------------------------------------------- + // New Image creation (no allocation) + template + typename itk::Image::Pointer NewImage1D(int size, double spacing=1.0); + template + typename itk::Image::Pointer NewImage2D(int sx, int sy, double dx=1.0, double dy=1.0); + template + typename itk::Image::Pointer NewImage3D(int sx, int sy, int sz, double dx=1.0, double dy=1.0, double dz=1.0); + template + typename itk::Image::Pointer NewImage4D(int sx, int sy, int sz, int st, double dx=1.0, double dy=1.0, double dz=1.0, double dt=1.0); + + //-------------------------------------------------------------------- + // New Image creation (with allocation) + + //-------------------------------------------------------------------- + // Read an Write image + // template + // typename ImageType::Pointer ReadImage(const std::string & filename, const bool verbose=false); + template + typename ImageType::Pointer readImage(const std::string & filename, const bool verbose=false); + template + typename ImageType::Pointer readImage(const std::vector & filenames, const bool verbose=false); + template + void writeImage(const typename ImageType::Pointer image, const std::string & filename, const bool verbose=false); +// template +// void writeConstImage(const typename ImageType::ConstPointer image, const std::string & filename, const bool verbose=false); + template + void writeImage(const ImageType* image, const std::string & filename, const bool verbose=false); + + //-------------------------------------------------------------------- + // Read/print image header + itk::ImageIOBase::Pointer readImageHeader(const std::string & filename); + void printImageHeader(itk::ImageIOBase::Pointer header, std::ostream & os, const int level=0); + + //-------------------------------------------------------------------- + // Determine pixetype and dimension of an image file + void ReadImageDimensionAndPixelType(const std::string & filename, int & dimension, std::string & pixeType); + + //-------------------------------------------------------------------- + // Determine pixetype, dimension and number of pixel components of an image file + void ReadImageDimensionAndPixelType(const std::string & filename, int & dimension, std::string & pixeType, int & components); + + //-------------------------------------------------------------------- + // Read a dicom header + gdcm::File * readDicomHeader(const std::string & filename, const bool verbose=false); + + //-------------------------------------------------------------------- + template + int ComputeHowManyDifferentIntensity(const typename ImageType::Pointer & image, + std::vector & listOfIntensities); + template + void ComputeWeightsOfEachClasses(const typename InputImageType::Pointer & input, + const typename MaskImageType::Pointer & mask, + const std::vector & listOfIntensities, + std::map > & mapOfLabelsAndWeights); + +#include "clitkImageCommon.txx" + +} // end namespace + +#endif /* end #define CLITKIMAGECOMMON_H */ + diff --git a/common/clitkImageCommon.txx b/common/clitkImageCommon.txx new file mode 100644 index 0000000..45e8c2e --- /dev/null +++ b/common/clitkImageCommon.txx @@ -0,0 +1,259 @@ +#ifndef CLITKIMAGECOMMON_TXX +#define CLITKIMAGECOMMON_TXX + +/** + ------------------------------------------------- + * @file clitkImageCommon.txx + * @author David Sarrut + * @date 07 Sep 2007 11:34:19 + * + * @brief + * + * + -------------------------------------------------*/ + +//-------------------------------------------------------------------- +template +typename itk::Image::Pointer NewImage1D(int vsize, double vspacing) { + typedef itk::Image ImageType; + typename ImageType::Pointer g = ImageType::New(); + typename ImageType::SizeType size; + size[0] = vsize; + typename ImageType::RegionType region; + region.SetSize(size); + g->SetRegions(region); + typename ImageType::SpacingType spacing; + spacing[0] = vspacing; + g->SetSpacing(spacing); + return g; +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +typename itk::Image::Pointer NewImage2D(int sx, int sy, double dx, double dy) { + typedef itk::Image ImageType; + typename ImageType::Pointer g = ImageType::New(); + typename ImageType::SizeType size; + size[0] = sx; size[1] = sy; + typename ImageType::RegionType region; + region.SetSize(size); + g->SetRegions(region); + typename ImageType::SpacingType spacing; + spacing[0] = dx; spacing[1] = dy; + g->SetSpacing(spacing); + return g; +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +typename itk::Image::Pointer NewImage3D(int sx, int sy, int sz, double dx, double dy, double dz) { + typedef itk::Image ImageType; + typename ImageType::Pointer g = ImageType::New(); + typename ImageType::SizeType size; + size[0] = sx; size[1] = sy; size[2] = sz; + typename ImageType::RegionType region; + region.SetSize(size); + g->SetRegions(region); + typename ImageType::SpacingType spacing; + spacing[0] = dx; spacing[1] = dy; spacing[2] = dz; + g->SetSpacing(spacing); + return g; +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +typename itk::Image::Pointer NewImage4D(int sx, int sy, int sz, int st, double dx, double dy, double dz, double dt) { + typedef itk::Image ImageType; + typename ImageType::Pointer g = ImageType::New(); + typename ImageType::SizeType size; + size[0] = sx; size[1] = sy; size[2] = sz; size[3] = st; + typename ImageType::RegionType region; + region.SetSize(size); + g->SetRegions(region); + typename ImageType::SpacingType spacing; + spacing[0] = dx; spacing[1] = dy; spacing[2] = dz; spacing[3] = dt; + g->SetSpacing(spacing); + return g; +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +typename ImageType::Pointer readImage(const std::string & filename, const bool verbose) { + typedef itk::ImageFileReader ReaderType; + typename ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(filename.c_str()); + if (verbose) { + std::cout << "Reading [" << filename << "] ... " << std::endl; + } + try { + reader->Update(); + } + catch(itk::ExceptionObject & err) { + std::cerr << "Exception while reading image [" << filename << "]" << std::endl; + std::cerr << err << std::endl; + exit(0); + } + return reader->GetOutput(); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +typename ImageType::Pointer readImage(const std::vector & filenames, + const bool verbose) { + if (filenames.size() == 1) return readImage(filenames[0], verbose); + typedef itk::ImageSeriesReader ReaderType; + typename ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileNames(filenames); + if (verbose) { + std::cout << "Reading " << filenames[0] << " and others ..." << std::endl; + } + try { + reader->Update(); + } + catch( itk::ExceptionObject & err ) { + std::cerr << "Error while reading " << filenames[0] + << " or other files ..." << err << std::endl; + exit(0); + } + return reader->GetOutput(); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +void writeImage(const typename ImageType::Pointer image, const std::string & filename, const bool verbose=false) { + typedef itk::ImageFileWriter WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(filename.c_str()); + writer->SetInput(image); + if (verbose) { + std::cout << "Writing [" << filename << "] ... " << std::endl; + } + try { + writer->Update(); + } + catch( itk::ExceptionObject & err ) { + std::cerr << "Exception while writing image [" << filename << "]" << std::endl; + std::cerr << err << std::endl; + exit(-1); + } +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +void writeImage(const ImageType* image, const std::string & filename, const bool verbose=false) { + typedef itk::ImageFileWriter WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(filename.c_str()); + writer->SetInput(image); + if (verbose) { + std::cout << "Writing [" << filename << "] ... " << std::endl; + } + try { + writer->Update(); + } + catch( itk::ExceptionObject & err ) { + std::cerr << "Exception while writing image [" << filename << "]" << std::endl; + std::cerr << err << std::endl; + exit(-1); + } +} +// //-------------------------------------------------------------------- + +// //-------------------------------------------------------------------- +// template +// void writeImage(const typename ImageType::ConstPointer image, const std::string & filename, const bool verbose=false) { +// typedef itk::ImageFileWriter WriterType; +// typename WriterType::Pointer writer = WriterType::New(); +// writer->SetFileName(filename.c_str()); +// writer->SetInput(image); +// if (verbose) { +// std::cout << "Writing [" << filename << "] ... " << std::endl; +// } +// try { +// writer->Update(); +// } +// catch( itk::ExceptionObject & err ) { +// std::cerr << "Exception while writing image [" << filename << "]" << std::endl; +// std::cerr << err << std::endl; +// exit(-1); +// } +// } + +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +// Compute the number of different intensities in an image +template +int ComputeHowManyDifferentIntensity(const typename ImageType::Pointer & image, + std::vector & l) +{ + //std::set listOfIntensities; + std::map listOfIntensities; + // listOfIntensities.resize(0); + typedef itk::ImageRegionConstIterator ConstIteratorType; + ConstIteratorType pi(image, image->GetLargestPossibleRegion()); + pi.Begin(); + while (!pi.IsAtEnd()) { + if (!listOfIntensities[pi.Get()]) listOfIntensities[pi.Get()] = true; + // if (std::find(listOfIntensities.begin(), + // listOfIntensities.end(), + // pi.Get()) == listOfIntensities.end()) { + // listOfIntensities.insert(pi.Get()); + // } + ++pi; + } + + //typename std::set::const_iterator ppi = listOfIntensities.begin(); + typename std::map::const_iterator ppi = listOfIntensities.begin(); + while (ppi != listOfIntensities.end()) { + l.push_back(ppi->first); + ++ppi; + } + + return listOfIntensities.size(); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +void ComputeWeightsOfEachClasses(const typename InputImageType::Pointer & input, + const typename MaskImageType::Pointer & mask, + const std::vector & listOfIntensities, + std::map > & mapOfLabelsAndWeights) { + // Check size + if (input->GetLargestPossibleRegion() != mask->GetLargestPossibleRegion()) { + itkGenericExceptionMacro(<< "Input and mask images have not the same size" + << std::endl + << "Input = " << input->GetLargestPossibleRegion() + << std::endl + << "Mask = " << mask->GetLargestPossibleRegion()); + } + + // reset weights list + mapOfLabelsAndWeights.clear(); + + // loop + typedef itk::ImageRegionConstIterator ConstInputIteratorType; + ConstInputIteratorType pi(input, input->GetLargestPossibleRegion()); + typedef itk::ImageRegionConstIterator ConstMaskIteratorType; + ConstMaskIteratorType pm(mask, mask->GetLargestPossibleRegion()); + pi.Begin(); + pm.Begin(); + while (!pi.IsAtEnd()) { + mapOfLabelsAndWeights[pm.Get()][pi.Get()]++; + ++pi; + ++pm; + } +} +//-------------------------------------------------------------------- + +#endif /* end #define CLITKIMAGECOMMON_TXX */ + diff --git a/common/clitkImageToImageGenericFilter.cxx b/common/clitkImageToImageGenericFilter.cxx new file mode 100644 index 0000000..0428c70 --- /dev/null +++ b/common/clitkImageToImageGenericFilter.cxx @@ -0,0 +1,90 @@ +#include "clitkImageToImageGenericFilter.h" +#include "clitkImageCommon.h" + +//-------------------------------------------------------------------- +clitk::ImageToImageGenericFilter::ImageToImageGenericFilter() : + mIOVerbose(false) +{} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::ImageToImageGenericFilter::SetInputFilenames(const std::vector & filenames) { + mInputFilenames.resize(filenames.size()); + std::copy(filenames.begin(), filenames.end(), mInputFilenames.begin()); +} + +void clitk::ImageToImageGenericFilter::SetInputFilename(const std::string & filename) { + std::vector f; + f.push_back(filename); + SetInputFilenames(f); +} + +void clitk::ImageToImageGenericFilter::AddInputFilename(const std::string & filename) { + mInputFilenames.push_back(filename); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::ImageToImageGenericFilter::SetOutputFilename(const std::string & filename) { + mOutputFilenames.clear(); + mOutputFilenames.push_back(filename); +} +void clitk::ImageToImageGenericFilter::AddOutputFilename(const std::string & filename) +{ + mOutputFilenames.push_back(filename); +} +void clitk::ImageToImageGenericFilter::SetOutputFilenames(const std::vector & filenames) +{ + std::copy(filenames.begin(), filenames.end(), mOutputFilenames.begin()); +} +std::string clitk::ImageToImageGenericFilter::GetOutputFilename() +{ + assert(mOutputFilenames.size() == 1); + return mOutputFilenames.front(); +} +//-------------------------------------------------------------------- +void clitk::ImageToImageGenericFilter::GetInputImageDimensionAndPixelType(unsigned int& dim,\ + std::string& pixeltype,unsigned int& components) +{ + if (mInputFilenames.size()) + { + int comp_temp,dim_temp; //clitkCommonImage takes ints + ReadImageDimensionAndPixelType(mInputFilenames[0], dim_temp, pixeltype,comp_temp); + components=comp_temp; dim=dim_temp; + } + else if (mInputVVImages.size()) + { + pixeltype=mInputVVImages[0]->GetScalarTypeAsString(); + dim=mInputVVImages[0]->GetNumberOfDimensions(); + components=mInputVVImages[0]->GetNumberOfScalarComponents(); + } + else + assert(false); //No input image, shouldn't happen +} +vvImage::Pointer clitk::ImageToImageGenericFilter::GetOutputVVImage () +{ + assert(mOutputVVImages.size()); + return mOutputVVImages[0]; +} + +std::vector clitk::ImageToImageGenericFilter::GetOutputVVImages() +{ + return mOutputVVImages; +} + +void clitk::ImageToImageGenericFilter::SetInputVVImage (vvImage::Pointer input) +{ + mInputVVImages.clear(); + mInputVVImages.push_back(input); +} + +void clitk::ImageToImageGenericFilter::AddInputVVImage (vvImage::Pointer input) +{ + mInputVVImages.push_back(input); +} + +void clitk::ImageToImageGenericFilter::SetInputVVImages (std::vector input) +{ + mInputVVImages=input; +} + diff --git a/common/clitkImageToImageGenericFilter.h b/common/clitkImageToImageGenericFilter.h new file mode 100644 index 0000000..43a62df --- /dev/null +++ b/common/clitkImageToImageGenericFilter.h @@ -0,0 +1,107 @@ +#ifndef CLITKIMAGETOIMAGEGENERICFILTER_H +#define CLITKIMAGETOIMAGEGENERICFILTER_H + +/** + =================================================================== + * @file clitkImageToImageGenericFilter.h + * @author David Sarrut + * @date 05 May 2008 14:40:51 + + * @brief + + ===================================================================*/ + +// clitk include +#include "clitkCommon.h" +#include "clitkImageCommon.h" +#include + +#include +#include +#include +#include + +namespace clitk { + + class ImageToImageGenericFilter: public itk::Object { + + public: + // constructor - destructor + ImageToImageGenericFilter(); + + // Types + typedef ImageToImageGenericFilter Self; + typedef Object Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + // Generic IO + /// Returns the dimension and pixel type of the *first* input + void GetInputImageDimensionAndPixelType(unsigned int& dim, std::string& pixeltype,unsigned int & components); + + // File IO + void SetInputFilename(const std::string & filename); + void AddInputFilename(const std::string & filename); + void SetInputFilenames(const std::vector & filenames); + void SetOutputFilename(const std::string & filename); + void AddOutputFilename(const std::string & filename); + void SetOutputFilenames(const std::vector & filenames); + std::string GetOutputFilename(); + void SetIOVerbose(bool b) { mIOVerbose = b; } + + // VVImage IO + void SetInputVVImage (vvImage::Pointer input); + void SetInputVVImages (std::vector input); + void AddInputVVImage (vvImage::Pointer input); + vvImage::Pointer GetOutputVVImage (); + std::vector GetOutputVVImages (); + + /// Main function to implement + virtual void Update() = 0; + + protected: + /// Call this function to dispatch an output towards the correct sink + template + void SetNextOutput(typename ImageType::Pointer output); + /// Call this function to get the nth itk input image, regardless of input source + template + typename ImageType::Pointer GetInput(unsigned int n); + + std::vector mInputFilenames; + std::list mOutputFilenames; + + bool mIOVerbose; + unsigned int mDim; + std::string mPixelTypeName; + unsigned int mNbOfComponents; + + std::vector mInputVVImages; + std::vector mOutputVVImages; + + }; // end class clitk::ImageToImageGenericFilter + +} // end namespace + +template +void clitk::ImageToImageGenericFilter::SetNextOutput(typename ImageType::Pointer output) +{ + if (mOutputFilenames.size()) + { + clitk::writeImage(output, mOutputFilenames.front(), mIOVerbose); + mOutputFilenames.pop_front(); + } + if (mInputVVImages.size()) //We assume that if a vv image is set as input, we want one as the output + mOutputVVImages.push_back(vvImageFromITK(output)); +} +template +typename ImageType::Pointer clitk::ImageToImageGenericFilter::GetInput(unsigned int n) +{ + if (mInputFilenames.size() > n) + return clitk::readImage(mInputFilenames[n], mIOVerbose); + else if (mInputVVImages.size() > n) + return typename ImageType::Pointer(const_cast(vvImageToITK(mInputVVImages[n]).GetPointer())); + else + assert(false); //No input, this shouldn't happen +} +#endif /* end #define CLITKIMAGETOIMAGEGENERICFILTER_H */ + diff --git a/common/clitkImageUtilities.cxx b/common/clitkImageUtilities.cxx new file mode 100644 index 0000000..4c8a576 --- /dev/null +++ b/common/clitkImageUtilities.cxx @@ -0,0 +1,36 @@ +/*========================================================================= + + Program: clitk + Module: $RCSfile: clitkImageUtilities.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:32:01 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef CLITKIMAGEUTILITIES_CXX +#define CLITKIMAGEUTILITIES_CXX + +/** + ================================================= + * @file clitkImageUtilities.cxx + * @author David Sarrut + * @date 22 Sep 2006 10:39:40 + * + * @brief + * + * + =================================================*/ + +#include "clitkImageUtilities.h" + +#endif /* end #define CLITKIMAGEUTILITIES_CXX */ + diff --git a/common/clitkImageUtilities.h b/common/clitkImageUtilities.h new file mode 100644 index 0000000..74c5b54 --- /dev/null +++ b/common/clitkImageUtilities.h @@ -0,0 +1,36 @@ +#ifndef CLITKIMAGEUTILITIES_H +#define CLITKIMAGEUTILITIES_H + +/** + =================================================================== + * @file clitkImageUtilities.h + * @author David Sarrut + * @date 22 Sep 2006 10:38:36 + + * @brief + + ===================================================================*/ + +// clitk +#include "clitkCommon.h" +#include "clitkImageCommon.h" + +// std +#include +#include +#include + +// itk +#include "itkImageRegionConstIterator.h" + +namespace clitk { + + template + int ComputeHowManyDifferentIntensity(const typename ImageType::Pointer & image, + std::vector & listOfIntensities); + #include "clitkImageUtilities.txx" + +} // end namespace + +#endif /* end #define CLITKIMAGEUTILITIES_H */ + diff --git a/common/clitkImageUtilities.txx b/common/clitkImageUtilities.txx new file mode 100644 index 0000000..884dab9 --- /dev/null +++ b/common/clitkImageUtilities.txx @@ -0,0 +1,105 @@ +#ifndef CLITKIMAGEUTILITIES_TXX +#define CLITKIMAGEUTILITIES_TXX + +/** + ================================================= + * @file clitkImageUtilities.txx + * @author David Sarrut + * @date 22 Sep 2006 10:39:48 + * + * @brief + * + * + =================================================*/ + +//==================================================================== +// Compute the number of different intensities in an image +template +int ComputeHowManyDifferentIntensity(const typename ImageType::Pointer & image, + std::vector & l) +{ + //std::set listOfIntensities; + std::map listOfIntensities; + // listOfIntensities.resize(0); + typedef itk::ImageRegionConstIterator ConstIteratorType; + ConstIteratorType pi(image, image->GetLargestPossibleRegion()); + pi.Begin(); + while (!pi.IsAtEnd()) { + if (!listOfIntensities[pi.Get()]) listOfIntensities[pi.Get()] = true; + // if (std::find(listOfIntensities.begin(), +// listOfIntensities.end(), +// pi.Get()) == listOfIntensities.end()) { +// listOfIntensities.insert(pi.Get()); +// } + ++pi; + } + + //typename std::set::const_iterator ppi = listOfIntensities.begin(); + typename std::map::const_iterator ppi = listOfIntensities.begin(); + while (ppi != listOfIntensities.end()) { + l.push_back(ppi->first); + ++ppi; + } + + return listOfIntensities.size(); +} +//==================================================================== + +//==================================================================== +template +void ComputeWeightsOfEachClasses(const typename InputImageType::Pointer & input, + const typename MaskImageType::Pointer & mask, + const std::vector & listOfIntensities, + std::map > & mapOfLabelsAndWeights) { + // Check size + if (input->GetLargestPossibleRegion() != mask->GetLargestPossibleRegion()) { + itkGenericExceptionMacro(<< "Input and mask images have not the same size" + << std::endl + << "Input = " << input->GetLargestPossibleRegion() + << std::endl + << "Mask = " << mask->GetLargestPossibleRegion()); + } + + // reset weights list + mapOfLabelsAndWeights.clear(); + + // loop + typedef itk::ImageRegionConstIterator ConstInputIteratorType; + ConstInputIteratorType pi(input, input->GetLargestPossibleRegion()); + typedef itk::ImageRegionConstIterator ConstMaskIteratorType; + ConstMaskIteratorType pm(mask, mask->GetLargestPossibleRegion()); + pi.Begin(); + pm.Begin(); + while (!pi.IsAtEnd()) { + mapOfLabelsAndWeights[pm.Get()][pi.Get()]++; + ++pi; + ++pm; + } +} +//==================================================================== + +// //==================================================================== +// template +// typename ImageType::Pointer NewImage3D(int x, int y, int z, float dx, float dy, float dz) { +// typename ImageType::Pointer output = ImageType::New(); +// typename ImageType::RegionType region; +// typename ImageType::SizeType size; +// size[0] = x; +// size[1] = y; +// size[2] = z; +// region.SetSize(size); +// output->SetRegions(region); +// output->Allocate(); +// typename ImageType::SpacingType spacing; +// spacing[0] = dx; +// spacing[1] = dy; +// spacing[2] = dz; +// output->SetSpacing(spacing); +// return output; +// } +// //==================================================================== + + +#endif /* end #define CLITKIMAGEUTILITIES_TXX */ + diff --git a/common/clitkListOfPair.cxx b/common/clitkListOfPair.cxx new file mode 100644 index 0000000..a240985 --- /dev/null +++ b/common/clitkListOfPair.cxx @@ -0,0 +1,66 @@ +/*------------------------------------------------------------------------= + + Program: clitk + Module: $RCSfile: clitkListOfPair.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:32:01 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +------------------------------------------------------------------------=*/ + + +#ifndef CLITKLISTOFPAIR_CXX +#define CLITKLISTOFPAIR_CXX + +/** + ------------------------------------------------= + * @file clitkListOfPair.cxx + * @author David Sarrut + * @date 27 Feb 2007 09:55:56 + * + * @brief + * + * + ------------------------------------------------=*/ + +#include "clitkListOfPair.h" + +//-------------------------------------------------------------------- +double clitk::convertValue(double v, + const std::multimap & conversionTable, + bool linear) { + std::map::const_iterator i; + i = conversionTable.lower_bound(v); + if (i == conversionTable.end()) { + std::cerr << "The value " << v << " is out of the table" << std::endl; + exit(0); + } + + double v2 = i->first; + double p2 = i->second; + if (i != conversionTable.begin()) i--; + double v1 = i->first; + double p1 = i->second; + + // interpol + if (!linear) { + if ((v-v1) > (v2-v)) return p2; + else return p1; + } + else { + double w = (v-v1)/(v2-v1); + return p1*(1.0-w)+w*p2; + } +} +//-------------------------------------------------------------------- + +#endif /* end #define CLITKLISTOFPAIR_CXX */ + diff --git a/common/clitkListOfPair.h b/common/clitkListOfPair.h new file mode 100644 index 0000000..4e9502f --- /dev/null +++ b/common/clitkListOfPair.h @@ -0,0 +1,32 @@ +#ifndef CLITKLISTOFPAIR_H +#define CLITKLISTOFPAIR_H + +/** + =================================================================== + * @file clitkListOfPair.h + * @author David Sarrut + * @date 27 Feb 2007 09:44:18 + + * @brief + + ===================================================================*/ + +#include "clitkCommon.h" + +namespace clitk { + + //==================================================================== + template + void ReadMap(const std::string & filename, MapType & list, bool inverse=false); + + //==================================================================== + double convertValue(double v, + const std::multimap & conversionTable, + bool linear); + +#include "clitkListOfPair.txx" + +} // end namespace + +#endif /* end #define CLITKLISTOFPAIR_H */ + diff --git a/common/clitkListOfPair.txx b/common/clitkListOfPair.txx new file mode 100644 index 0000000..d711cc5 --- /dev/null +++ b/common/clitkListOfPair.txx @@ -0,0 +1,39 @@ +#ifndef CLITKLISTOFPAIR_TXX +#define CLITKLISTOFPAIR_TXX + +/** + ================================================= + * @file clitkListOfPair.txx + * @author David Sarrut + * @date 27 Feb 2007 09:44:48 + * + * @brief + * + * + =================================================*/ + +//==================================================================== +template +void ReadMap(const std::string & filename, MapType & list, bool inverse) { + std::ifstream is; + clitk::openFileForReading(is, filename); + clitk::skipComment(is); + typedef typename MapType::key_type KType; + KType v1; + typedef typename MapType::mapped_type MType; + MType v2; + while (is) { + is >> v1; + is >> v2; + if (is) { + if (!inverse) list.insert(std::pair(v1,v2)); + else list.insert(std::pair(v2,v1)); + } + clitk::skipComment(is); + } + is.close(); +} +//==================================================================== + +#endif /* end #define CLITKLISTOFPAIR_TXX */ + diff --git a/common/clitkOrientation.cxx b/common/clitkOrientation.cxx new file mode 100644 index 0000000..c887eb7 --- /dev/null +++ b/common/clitkOrientation.cxx @@ -0,0 +1,184 @@ +/*========================================================================= + +Program: clitk +Module: $RCSfile: clitkOrientation.cxx,v $ +Language: C++ +Date: $Date: 2010/01/06 13:32:01 $ +Version: $Revision: 1.1 $ + +Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de +l'Image). All rights reserved. See Doc/License.txt or +http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef CLITKORIENTATION_CXX +#define CLITKORIENTATION_CXX + +/** + ================================================= + * @file clitkOrientation.cxx + * @author David Sarrut + * @date 01 Nov 2006 18:02:49 + * + * @brief + * + * + =================================================*/ + +#include "clitkOrientation.h" + +//==================================================================== +itk::SpatialOrientation::CoordinateTerms clitk::GetOrientation(char c) +{ + if ((c == 'R') || (c == 'r')) return itk::SpatialOrientation::ITK_COORDINATE_Right; + if ((c == 'L') || (c == 'l')) return itk::SpatialOrientation::ITK_COORDINATE_Left; + if ((c == 'P') || (c == 'p')) return itk::SpatialOrientation::ITK_COORDINATE_Posterior; + if ((c == 'A') || (c == 'a')) return itk::SpatialOrientation::ITK_COORDINATE_Anterior; + if ((c == 'I') || (c == 'i')) return itk::SpatialOrientation::ITK_COORDINATE_Inferior; + if ((c == 'S') || (c == 's')) return itk::SpatialOrientation::ITK_COORDINATE_Superior; + std::cerr <<"I don't know the orientation '" << c + << "'. Valid letters are LR/AP/IS (or in lowercase)" << std::endl; + exit(0); +} +//==================================================================== + +//==================================================================== +bool clitk::CheckOrientation(itk::SpatialOrientation::CoordinateTerms a, + itk::SpatialOrientation::CoordinateTerms b) +{ + if ((a==itk::SpatialOrientation::ITK_COORDINATE_Right) || + (a==itk::SpatialOrientation::ITK_COORDINATE_Left)) { + if ((b==itk::SpatialOrientation::ITK_COORDINATE_Right) || + (b==itk::SpatialOrientation::ITK_COORDINATE_Left)) { + return false; + } + } + if ((a==itk::SpatialOrientation::ITK_COORDINATE_Posterior) || + (a==itk::SpatialOrientation::ITK_COORDINATE_Anterior)) { + if ((b==itk::SpatialOrientation::ITK_COORDINATE_Posterior) || + (b==itk::SpatialOrientation::ITK_COORDINATE_Anterior)) { + return false; + } + } + if ((a==itk::SpatialOrientation::ITK_COORDINATE_Inferior) || + (a==itk::SpatialOrientation::ITK_COORDINATE_Superior)) { + if ((b==itk::SpatialOrientation::ITK_COORDINATE_Inferior) || + (b==itk::SpatialOrientation::ITK_COORDINATE_Superior)) { + return false; + } + } + return true; +} +//==================================================================== + +//==================================================================== +itk::SpatialOrientation::ValidCoordinateOrientationFlags clitk::GetOrientation(char a, char b, char c) +{ + itk::SpatialOrientation::CoordinateTerms f1 = clitk::GetOrientation(a); + itk::SpatialOrientation::CoordinateTerms f2 = clitk::GetOrientation(b); + itk::SpatialOrientation::CoordinateTerms f3 = clitk::GetOrientation(c); + + if (CheckOrientation(f1, f2) && CheckOrientation(f2,f3) && CheckOrientation(f1,f3)) { + return static_cast( + (f1 << itk::SpatialOrientation::ITK_COORDINATE_PrimaryMinor) + + (f2 << itk::SpatialOrientation::ITK_COORDINATE_SecondaryMinor) + + (f3 << itk::SpatialOrientation::ITK_COORDINATE_TertiaryMinor)); + } + std::cerr <<"I don't know the orientation '" << a << b << c + << "'. Valid letters are LR/AP/IS (or in lowercase)" << std::endl; + exit(0); +} +//==================================================================== + +//==================================================================== +itk::SpatialOrientation::ValidCoordinateOrientationFlags clitk::GetOrientation(const std::string & orient) +{ + if (orient.size() >= 3) return GetOrientation(orient[0], orient[1], orient[2]); + std::cerr <<"I don't know the orientation '" << orient + << "'. Valid string are three letters LR/AP/IS (or in lowercase)" << std::endl; + exit(0); +} +//==================================================================== + +//==================================================================== +itk::SpatialOrientation::CoordinateTerms clitk::GetOrientation(const int i, const itk::SpatialOrientation::ValidCoordinateOrientationFlags orient) +{ + if (i==0) return static_cast((orient << 24) >> 24); + if (i==1) return static_cast((orient << 16) >> 24); + if (i==2) return static_cast(orient >> 16); + std::cerr <<"Invalid index = " << i << " in GetOrientation" << std::endl; + exit(0); +} +//==================================================================== + +//==================================================================== +int clitk::WhereIsDimInThisOrientation(const int dim, const itk::SpatialOrientation::ValidCoordinateOrientationFlags flag) { + if (dim ==0) { + for(int i=0; i<3; i++) { + int j = GetOrientation(i, flag); + if ((j == itk::SpatialOrientation::ITK_COORDINATE_Right) || + (j == itk::SpatialOrientation::ITK_COORDINATE_Left)) return i; + } + } + if (dim ==1) { + for(int i=0; i<3; i++) { + int j = GetOrientation(i, flag); + if ((j == itk::SpatialOrientation::ITK_COORDINATE_Anterior) || + (j == itk::SpatialOrientation::ITK_COORDINATE_Posterior)) return i; + } + } + if (dim ==2) { + for(int i=0; i<3; i++) { + int j = GetOrientation(i, flag); + if ((j == itk::SpatialOrientation::ITK_COORDINATE_Superior) || + (j == itk::SpatialOrientation::ITK_COORDINATE_Inferior)) return i; + } + } + return 0; // just to avoid warning +} +//==================================================================== + +//==================================================================== +int clitk::GetDim(const itk::SpatialOrientation::CoordinateTerms t) +{ + if ((t == itk::SpatialOrientation::ITK_COORDINATE_Right) || + (t == itk::SpatialOrientation::ITK_COORDINATE_Left)) return 0; + if ((t == itk::SpatialOrientation::ITK_COORDINATE_Anterior) || + (t == itk::SpatialOrientation::ITK_COORDINATE_Posterior)) return 1; + if ((t == itk::SpatialOrientation::ITK_COORDINATE_Inferior) || + (t == itk::SpatialOrientation::ITK_COORDINATE_Superior)) return 2; + std::cerr <<"Invalid CoordinateTerms = " << t << std::endl; + exit(0); +} +//==================================================================== + +//==================================================================== +void clitk::FlipPoint(const itk::Point in, + const itk::SpatialOrientation::ValidCoordinateOrientationFlags inFlag, + const itk::SpatialOrientation::ValidCoordinateOrientationFlags outFlag, + const itk::Point & imageSize, + itk::Point & out) +{ + for(int i=0; i<3; i++) { + // DD(i); + itk::SpatialOrientation::CoordinateTerms inT = GetOrientation(i, inFlag); + // DD(inT); + int inDim = GetDim(inT); + // DD(inDim); + int outDim = WhereIsDimInThisOrientation(inDim, outFlag); + // DD(outDim); + // DD(in[i]); + if (inT == GetOrientation(outDim, outFlag)) out[outDim] = in[i]; + else out[outDim] = imageSize[i]-in[i]; + // DD(out[outDim]); + } +} +//==================================================================== + +#endif /* end #define CLITKORIENTATION_CXX */ + diff --git a/common/clitkOrientation.h b/common/clitkOrientation.h new file mode 100644 index 0000000..250e6fe --- /dev/null +++ b/common/clitkOrientation.h @@ -0,0 +1,56 @@ +#ifndef CLITKORIENTATION_H +#define CLITKORIENTATION_H + +/** + =================================================================== + * @file clitkOrientation.h + * @author David Sarrut + * @date 01 Nov 2006 18:00:32 + + * @brief + + ===================================================================*/ + +// itk include +#include "itkSpatialOrientation.h" +#include "itkPoint.h" + +namespace clitk { + + //==================================================================== + // From a letter to an SpatialOrientation::CoordinateTerms + itk::SpatialOrientation::CoordinateTerms GetOrientation(char c); + + //==================================================================== + // From three letters to an SpatialOrientation + itk::SpatialOrientation::ValidCoordinateOrientationFlags GetOrientation(char a, char b, char c); + itk::SpatialOrientation::ValidCoordinateOrientationFlags GetOrientation(const std::string & orient); + + //==================================================================== + // Check that the orientations are differents + bool CheckOrientation(itk::SpatialOrientation::CoordinateTerms a, itk::SpatialOrientation::CoordinateTerms b); + + //==================================================================== + // Get orientation at position i + itk::SpatialOrientation::CoordinateTerms GetOrientation(const int i, const itk::SpatialOrientation::ValidCoordinateOrientationFlags orient); + + //==================================================================== + // Find where is the dimension Dim in this orientaof orientation + int WhereIsDimInThisOrientation(const int dim, const itk::SpatialOrientation::ValidCoordinateOrientationFlags flag); + + //==================================================================== + // Flip point coordinate + void FlipPoint(const itk::Point in, + const itk::SpatialOrientation::ValidCoordinateOrientationFlags inFlag, + const itk::SpatialOrientation::ValidCoordinateOrientationFlags outFlag, + const itk::Point & imageSize, + itk::Point & out); + + //==================================================================== + // Get the dimension of this term + int GetDim(const itk::SpatialOrientation::CoordinateTerms t); + +} // end namespace + +#endif /* end #define CLITKORIENTATION_H */ + diff --git a/common/clitkSignal.cxx b/common/clitkSignal.cxx new file mode 100644 index 0000000..9f65bbf --- /dev/null +++ b/common/clitkSignal.cxx @@ -0,0 +1,1095 @@ +#ifndef CLITKSIGNAL_CXX +#define CLITKSIGNAL_CXX + +#include "clitkSignal.h" + +namespace clitk { + + //--------------------------------------------------------------------- + void Signal::Read(string fileName){ + ifstream signalStream(fileName.c_str()); + SignalValueType point; + if(!signalStream.is_open()){ + std::cerr << "ERROR: Couldn't open file " << fileName << " in Signal::Read" << std::endl; + return; + } + skipComment(signalStream); + while(!signalStream.eof()) { + skipComment(signalStream); + signalStream >> point; + skipComment(signalStream); + m_Data.push_back(point); + // cout << point << endl; + } + signalStream.close(); + SetSamplingPeriod(1.); + } + //--------------------------------------------------------------------- + + + //--------------------------------------------------------------------- + void Signal::Read(string fileName, int col){ + ifstream signalStream(fileName.c_str()); + SignalValueType point; + if(!signalStream.is_open()){ + std::cerr << "ERROR: Couldn't open file " << fileName << " in Signal::Read" << std::endl; + return; + } + skipComment(signalStream); + while(!signalStream.eof()) { + skipComment(signalStream); + + // Read one line + std::string line; + std::getline(signalStream, line); + + // Get column nb col + istringstream iss(line); + for(int i=0; i> sub; + } + iss >> point; + if (!iss) { + std::cerr << "ERROR: no col n" << col << " in the line '" << line << "' ?" << std::endl; + exit(0); + } + skipComment(signalStream); + m_Data.push_back(point); + // cout << point << endl; + } + signalStream.close(); + SetSamplingPeriod(1.); + } + //--------------------------------------------------------------------- + + + + //--------------------------------------------------------------------- + //Convert 1D image to signal + Signal Signal::ConvertImageToSignal( Signal::ImageType::Pointer image) + { + //empty signal + Signal signal; + + //make an image iterator + itk::ImageRegionConstIterator it(image,image->GetLargestPossibleRegion()); + it.Begin(); + + //copy + while(!it.IsAtEnd()) + { + signal.push_back(it.Get()); + ++it; + } + + //Spacing + signal.SetSamplingPeriod(image->GetSpacing()[0]); + + return signal; + } + //--------------------------------------------------------------------- + + + //--------------------------------------------------------------------- + //Convert 1D signal to image + Signal::ImageType::Pointer Signal::ConvertSignalToImage(Signal signal) + { + //empty image + ImageType::Pointer image =ImageType::New(); + ImageType::RegionType region; + ImageType::RegionType::IndexType index; + index[0]=0; + ImageType::RegionType::SizeType size; + size[0]=signal.size(); + + region.SetIndex(index); + region.SetSize(size); + + image->SetRegions(region); + image->Allocate(); + + //make an image iterator + itk::ImageRegionIterator mIt(image,image->GetLargestPossibleRegion()); + mIt.Begin(); + + //make a signal iterator + Signal::const_iterator sIt=signal.begin(); + + //copy + while(sIt!=signal.end()) + { + mIt.Set(*sIt); + sIt++;++mIt; + } + + + //spacing + ImageType::SpacingType spacing; + spacing[0]=signal.GetSamplingPeriod(); + image->SetSpacing(spacing); + + return image; + + } + //--------------------------------------------------------------------- + + + + //--------------------------------------------------------------------- + void Signal::Write(const string fileName){ + ofstream signalStream(fileName.c_str()); + if(!signalStream.is_open()){ + cerr << "ERROR: Couldn't open file " << fileName << " in Signal::Write" << endl; + return; + } + + iterator it=begin(); + while(it!=end()) { + signalStream << *it << endl; + it++; + } + signalStream.close(); + } + //--------------------------------------------------------------------- + + + //--------------------------------------------------------------------- + Signal & Signal::operator/=(Signal & div){ + if(size()!= div.size()) + { + std::cerr << "Error: signal size must be the same!" << std::endl; + return *this; + } + iterator it=begin(); + iterator itD; + itD=div.begin(); + while(it!=end()) + { + if(*itD!=0) + *it/=*itD; + else + cerr << "Division by 0 in operator/= skipped" << endl; + it++;itD++; + } + return *this; + } + //--------------------------------------------------------------------- + + + //--------------------------------------------------------------------- + Signal & Signal::operator*=(Signal & mul){ + if(size()!= mul.size()) + { + std::cerr << "Error: signal size must be the same!" << std::endl; + return *this; + } + iterator it=begin(); + iterator itD; + itD=mul.begin(); + while(it!=end()){ + *it *= *itD; + it++;itD++; + } + return *this; + } + //--------------------------------------------------------------------- + + + //--------------------------------------------------------------------- + Signal Signal::Normalize(double newMin,double newMax){ + Signal temp (m_SamplingPeriod); + vector extrema=GetGlobalMinMax(); + iterator itSig=begin(); + while(itSig!=end()){ + temp.push_back( ((*itSig)-extrema[0])*(newMax-newMin)/(extrema[1]-extrema[0]) + newMin ); + itSig++; + } + return temp; + } + //--------------------------------------------------------------------- + + + //--------------------------------------------------------------------- + vector Signal::GetGlobalMinMax() const { + vector extrema(2); + if(size()==0){ + cerr << "ERROR: GetExtrema / No signal" << endl; + return extrema; + } + extrema[0]=m_Data[0]; + extrema[1]=m_Data[0]; + for(unsigned int i=1;im_Data[i]) extrema[0]=m_Data[i]; + if(extrema[1](i)-static_cast(length)); j<=min(size(), i+length); j++) + { + accumulator+=m_Data[j]; + scale++; + } + temp.push_back(accumulator/scale); + } + return temp; + } + //--------------------------------------------------------------------- + + + //--------------------------------------------------------------------- + Signal Signal::GaussLikeFilter ( ) { + + Signal temp(m_SamplingPeriod); + if (size()<2) + return *this; + else + { + //first sample: mirrorring BC + temp.push_back((2.*m_Data[0]+2*m_Data[1])/4.); + + //middle samples + for (unsigned int i=1; i (size())*sampPeriod); + + //forward fft with empty fft + if(fft.size()==0) OneDForwardFourier(*this, fft); + + //remove the frequencies + for(unsigned int i=0;i(0.,0.); + + //backward with remaining frequencies + OneDBackwardFourier(fft,temp); + return temp; + } + //--------------------------------------------------------------------- + + + //--------------------------------------------------------------------- + Signal Signal::LowPassFilter (double sampPeriod, double cutOffFrequency ) + { + //output + Signal temp(m_SamplingPeriod); + temp.resize(size()); + + //the fft + SIGNAL_FFT_TYPE fft; + + //calculate the cut off frequency + unsigned int samp=lrint(cutOffFrequency*static_cast(size())*sampPeriod); + + //forward fft with empty fft + if(fft.size()==0) OneDForwardFourier(*this, fft); + unsigned int fsize=fft.size(); + + //remove the frequencies + unsigned int limit=min (samp, fsize); + for(unsigned int i=limit;i(0.,0.); + + //backward with remaining frequencies + OneDBackwardFourier(fft,temp); + return temp; + } + //--------------------------------------------------------------------- + + + //--------------------------------------------------------------------- + void Signal::OneDForwardFourier(const Signal& input, SIGNAL_FFT_TYPE & fft) + { + //Create output array + fft.resize(input.size()/2+1); + //Temp copy + double *tempCopy=new double[size()]; + copy(begin(), end(), tempCopy); + + //Forward Fourier Transform + fftw_plan p; + p=fftw_plan_dft_r2c_1d(size(),tempCopy,reinterpret_cast(&(fft[0])),FFTW_ESTIMATE); + fftw_execute(p); + fftw_destroy_plan(p); + //delete tempCopy; + return; + } + //--------------------------------------------------------------------- + + + //--------------------------------------------------------------------- + void Signal::OneDBackwardFourier(SIGNAL_FFT_TYPE & fft, Signal &output) + { + + //Backward + fftw_plan p; + p=fftw_plan_dft_c2r_1d(output.size(),reinterpret_cast(&(fft[0])),&(output[0]),FFTW_ESTIMATE); + fftw_execute(p); + fftw_destroy_plan(p); + + vector::iterator it=output.begin(); + while(it!=output.end()){ + *it /= (double)output.size(); + it++; + } + return; + } + //--------------------------------------------------------------------- + + + //--------------------------------------------------------------------- + double Signal::MaxFreq(const Signal &sig,SIGNAL_FFT_TYPE & fft) + { + + if(fft.size()==0) OneDForwardFourier(sig,fft); + int posMax=1; + double amplitude, amplitudeMax=abs(fft[1]); + for(unsigned int i=1;iamplitudeMax){ + posMax=i; + amplitudeMax=amplitude; + } + } + return ((double)(posMax)/((double)sig.size()*sig.GetSamplingPeriod())); + } + //--------------------------------------------------------------------- + + + //--------------------------------------------------------------------- + Signal Signal::DetectLocalExtrema(unsigned int width) + { + Signal temp(m_SamplingPeriod); + bool isMin, isMax; + unsigned int upper, lower; + + //has to be at least 1 + width=max(static_cast(width), 1); + + for(unsigned int i=0 ; i < size() ; i++){ + isMax=true; + isMin=true; + + for(unsigned int j=1; j< width+1; j++) + { + //set the boundaries + upper = min( size(), i+j); + lower = max( static_cast(0), (int)i-(int)j); + + //check if max + if( ! (m_Data[i] >= m_Data[lower] && m_Data[i] >= m_Data[upper]))isMax=false; + + //check if min + if( ! (m_Data[i]<= m_Data[lower] && m_Data[i] <= m_Data[upper])) isMin=false; + + //if neither, go to the next value + if( (!isMax) && (!isMin)) break; + } + + if (isMax) temp.push_back(1); + else if (isMin) temp.push_back(0); + else temp.push_back(0.5); + } + return temp; + } + //--------------------------------------------------------------------- + + + //--------------------------------------------------------------------- + Signal Signal::LimPhase() + { + + //phase is defined as going from 0 to 1 linearly between end expiration + Signal phase(m_SamplingPeriod); + phase.resize(size()); + + unsigned int firstBeginCycle=0; + unsigned int firstEndCycle=0; + unsigned int beginCycle=0; + + //========================================= + //Search the first value in extrema not 0.5 + while(m_Data[beginCycle]!=1) + { + beginCycle++; + } + + //We search the corresponding end + unsigned int endCycle=beginCycle+1; + while(endCycle != size() && m_Data[endCycle]!=1){ + endCycle++; + + } + + //============================================================ + //Calculate phase at the beginning (before the first extremum) + for(unsigned int i=0 ; i 1) + { + phase[i] = (double)(i-0)/(double)(beginCycle-0); + } + //copy the phase values later + else + { + firstBeginCycle=beginCycle; + firstEndCycle=endCycle; + } + + } + + //=================================================================== + //Middle part + while(endCycle != size()){ + + //fill between extrema + for(unsigned int i=beginCycle ; i 1){ + + //make the last part go till 1 + phase[i] = (double)(i-endCycle)/(double)(size()-endCycle); + } + + //the last part is shorter, copy the last cycle values + else{ + phase[i] = phase[i -(endCycle-beginCycle)]; + } + } + + //=================================================================== + //check it some remains to be copied in the beginning + if (firstBeginCycle!=0) + { + for(unsigned int i=0 ; i 1) + { + phase[i] = (double)(i-0)/(double)(beginCycle-0); + } + //copy the phase values later + else + { + firstBeginCycle=beginCycle; + firstEndCycle=endCycle; + } + + } + + //=================================================================== + //Middle part + while(endCycle != size()){ + + cycleCounter++; + //fill between extrema + for(unsigned int i=beginCycle ; i 1){ + + //make the last part go till 1 + phase[i] = (double)cycleCounter+(double)(i-endCycle)/(double)(size()-endCycle); + } + + //the last part is shorter, copy the last cycle values + else{ + phase[i] = phase[i -(endCycle-beginCycle)]+1; + } + } + + //=================================================================== + //check it some remains to be copied in the beginning + if (firstBeginCycle!=0) + { + for(unsigned int i=0 ; iMonPhase(); + + //Create an empty signal + Signal phase(size(), -1); + phase.SetSamplingPeriod(m_SamplingPeriod); + + //Fill in the values at the extrema position + iterator phaseIt=phase.begin(); + iterator monPhaseIt=monPhase.begin(); + iterator extremaIt =begin(); + while (extremaIt!= end()) + { + if (*extremaIt==0.) *phaseIt=eIPhaseValue+floor(*monPhaseIt); + else if (*extremaIt==1.) *phaseIt=eEPhaseValue+floor(*monPhaseIt); + extremaIt++; phaseIt++;monPhaseIt++; + } + + return phase; + + } + //--------------------------------------------------------------------- + + + //--------------------------------------------------------------------- + Signal Signal::LinearlyInterpolateScatteredValues() + { + //Linearly interpolate the values in between + unsigned int i=0; + unsigned int beginCycle=0; + unsigned int endCycle=0; + + //Create a new signal + Signal temp(size(),-1); + temp.SetSamplingPeriod(m_SamplingPeriod); + + //start from the first value + while (m_Data[i]==-1)i++; + beginCycle=i; + i++; + + //Go to the next + while ( (m_Data[i]==-1) && (i PointSetType; +// PointSetType::Pointer pointSet=PointSetType::New(); +// typedef PointSetType::PointType PointType; + +// unsigned int i=0; +// unsigned int pointIndex=0; +// while (i< size()) +// { +// if(m_Data[i]!=-1) +// { +// PointType p; +// p[0]= i;//JV spacing is allways 1 +// pointSet->SetPoint( pointIndex, p ); +// pointSet->SetPointData( pointIndex, m_Data[i] ); +// pointIndex++; +// } +// i++; +// } + +// //define the output signal properties +// ImageType::RegionType::SizeType outputSize; +// outputSize[0]= size(); +// ImageType::PointType outputOrigin; +// outputOrigin[0]=0.0;//JV may need to be changed +// ImageType::SpacingType outputSpacing; +// outputSpacing[0]=1; //JV add relation to the original signal spacing + +// //Convert +// typedef itk::BSplineScatteredDataPointSetToImageFilter< PointSetType, VectorImageType > PointSetToImageFilterType; +// PointSetToImageFilterType::Pointer pointSetToImageFilter= PointSetToImageFilterType::New(); +// pointSetToImageFilter->SetInput(pointSet); +// pointSetToImageFilter->SetSplineOrder(splineOrder);//JV +// pointSetToImageFilter->SetSize(outputSize); +// pointSetToImageFilter->SetOrigin(outputOrigin); +// pointSetToImageFilter->SetSpacing(outputSpacing); + +// //Convert to +// itk::FixedArray num; +// num[0]=numberOfControlPoints; +// pointSetToImageFilter->SetNumberOfControlPoints(num);//JV +// pointSetToImageFilter->Update(); +// VectorImageType::Pointer approximatedSignal=pointSetToImageFilter->GetOutput(); + +// //Convert and return +// return ConvertVectorImageToSignal(approximatedSignal); +// } +// //--------------------------------------------------------------------- + + + //--------------------------------------------------------------------- + Signal Signal::ConvertVectorImageToSignal(VectorImageType::Pointer image) + { + //empty signal + Signal signal; + + //make an image iterator + itk::ImageRegionConstIterator it(image,image->GetLargestPossibleRegion()); + it.Begin(); + + //copy + while(!it.IsAtEnd()) + { + signal.push_back(it.Get()[0]); + ++it; + } + + //Spacing + signal.SetSamplingPeriod(image->GetSpacing()[0]); + + return signal; + } + //--------------------------------------------------------------------- + + + //--------------------------------------------------------------------- + Signal Signal::LimitSignalRange() + { + //empty signal + Signal signal(m_SamplingPeriod); + iterator it=begin(); + while(it != end()) + { + signal.push_back(*it-floor(*it)); + it++; + } + return signal; + } + + + //--------------------------------------------------------------------- + double Signal::SSD(const Signal &sig2) const{ + if(sig2.size() != size()){ + cerr << "ERROR in Signal::SSD: signals don't have the same size" << endl; + return -1; + } + double result=0.; + for(unsigned int i=0;i(*(it+pos))) + // return -1*pos; + // } + + // void Signal::CenteredFiniteDifferences(Signal & result,int order,int* weights){ + // const_iterator itSig=begin()+order; + // result.resize(size()); + // iterator itDer=result.begin()+order; + // while(itSig!=end()-order){ + // (*itDer)=0.; + // for(int i=-order;i<=order;i++){ + // *itDer+=*(itSig-i)*weights[i+order]; + // } + // itSig++;itDer++; + // } + // } + + // void Signal::FirstDerivate(Signal & result,int order){ + // if(order==1){ + // int weights[3]={-1,0,1}; + // CenteredFiniteDifferences(result,order,weights); + // } + // else if(order==2){ + // int weights[5]={1,-8,0,8,-1}; + // CenteredFiniteDifferences(result,order,weights); + // } + // } + + // void Signal::SecondDerivate(Signal & result,int order){ + // if(order==1){ + // int weights[3]={1,-2,1}; + // CenteredFiniteDifferences(result,order,weights); + // } + // else if(order==2){ + // int weights[5]={-1,16,-30,16,-1}; + // CenteredFiniteDifferences(result,order,weights); + // } + // } + + + + // void Signal::NormalizeMeanStdDev(double newMean,double newStdDev){ + // iterator itSig=begin(); + // double sum=0, sum2=0; + // while(itSig!=end()){ + // sum += *itSig; + // sum2 += (*itSig) * (*itSig); + // itSig++; + // } + // double oldMean=sum/size(); + // double oldStdDev=sqrt(sum2/size()-oldMean*oldMean); + + // double a = newStdDev/oldStdDev; + // double b = newMean - a * oldMean; + // itSig=begin(); + // while(itSig!=end()){ + // *itSig = a *(*itSig) + b; + // itSig++; + // } + // } + + + + // void Signal::print(ostream & os, const int level) const { + // os << "Size:" << m_Data.size() << endl; + // const_iterator it=m_Data.begin(); + // while(it!=m_Data.end()){ + // os << *it << endl; + // it++; + // } + // } + + + // // } + + // // istream& Signal::get(istream& is) { + // // ERROR << "Signal::get NOT IMPLEMENTED"; + // // FATAL(); + // // return is; + // // } //// + + // // /** @b GridBase::put os + // // * @param os + // // * @return + // // ***************************************************/ + // // ostream& Signal::put(ostream& os) const { + // // print(os); + // // return os; + // // } //// + + + + // void Signal::Crop(unsigned int posmin, unsigned int posmax){ + // if(posmin >= m_Data.size()) return; + // if(posmax >= m_Data.size()) posmax=m_Data.size(); + // m_Data.erase(m_Data.begin()+posmax+1,m_Data.end()); + // m_Data.erase(m_Data.begin(),m_Data.begin()+posmin); + // } + + // void Signal::LinearResample(const unsigned int newSize){ + // SIGNAL newData; + // newData.push_back(front()); + // double posInOld,leftWeight,rightWeight; + // int leftPos, rightPos; + // for(unsigned int i=1 ; i < newSize-1 ; i++){ + // posInOld = (double)(i * (size()-1)) / (double)(newSize-1); + // leftPos = (int)floor(posInOld); + // rightPos = leftPos+1; + // leftWeight = (double)rightPos - posInOld; + // rightWeight = posInOld - (double)leftPos; + // newData.push_back(m_Data[leftPos] * leftWeight + m_Data[rightPos] * rightWeight ); + // } + + // newData.push_back(back()); + // m_Data=newData; + // } + + + // int Signal::FreqToSamp(double freq){ + // if(m_SamplingPeriod==-1.) + // cerr << "ERROR: you did not initialize the sampling period" << endl; + // return lrint(freq*(double)size()*m_SamplingPeriod); + // } + // double Signal::SampToFreq(int samp){ + // if(m_SamplingPeriod==-1.) + // cerr << "ERROR: you did not initialize the sampling period" << endl; + // return ((double)(samp)/((double)size()*m_SamplingPeriod)); + // } + +// //--------------------------------------------------------------------- +// Signal Signal::limPhaseDE(eIPhaseValue, eEPhaseValue) +// { + +// //Create an empty signal +// phase.resize(size()); + +// iterator phaseIt=initialPhaseValues.begin(); +// iterator monPhaseIt=monPhase.begin(); +// iterator extremaIt =begin(); + +// while (extremaIt!= end()) +// { +// if (*extremaIt==0.) *phaseIt=eIPhaseValue+floor(*monPhaseIt); +// else if (*extremaIt==1.) *phaseIt=eEPhaseValue+floor(*monPhaseIt); +// extremaIt++; phaseIt++;monPhaseIt++; +// } + +// } + + +} + +#endif //#define CLITKSIGNAL diff --git a/common/clitkSignal.h b/common/clitkSignal.h new file mode 100644 index 0000000..c955936 --- /dev/null +++ b/common/clitkSignal.h @@ -0,0 +1,130 @@ +#ifndef CLITKSIGNAL_H +#define CLITKSIGNAL_H + +//Adapted from Signal.hh in ilr (Simon) + +#include "clitkCommon.h" +#include "clitkIO.h" + +//include external library +#include +#include + +//itk include +#include "itkImage.h" +#include "itkImageRegionConstIterator.h" +#include "itkPointSet.h" +// #include "itkBSplineScatteredDataPointSetToImageFilter.h" + +using namespace std; + +namespace clitk{ + +class Signal{ + public: + + //===================================================================================== + //Typedefs + typedef double SignalValueType; + typedef vector< SignalValueType > SignalType; + typedef SignalType::iterator iterator; + typedef SignalType::const_iterator const_iterator; + typedef vector< complex > SIGNAL_FFT_TYPE; + + typedef itk::Image ImageType; + typedef itk::Vector VectorType; + typedef itk::Image VectorImageType; + + //===================================================================================== + //Constructors - Destructors + Signal(){SetSamplingPeriod(1.);} + Signal(double sp):m_SamplingPeriod(sp){;} + Signal(const string fileName){Read(fileName);} + Signal(unsigned int size, SignalValueType voidValue=0.) + { + m_Data.resize(size,voidValue); + SetSamplingPeriod(1); + }; + + ~Signal(){} + + //===================================================================================== + //IO + void Read(string fileName); + void Read(string fileName, int col); + void ReadXDR(string fileName); + void Write(const string fileName); + + //===================================================================================== + //Common vector properties for signals + unsigned int size() const {return m_Data.size();} + iterator begin(){return m_Data.begin();} + iterator end() {return m_Data.end();} + const_iterator begin() const {return m_Data.begin();} + const_iterator end() const {return m_Data.end();} + SignalValueType front() {return m_Data.front();} + SignalValueType back() {return m_Data.back();} + void push_back(SignalValueType value){return m_Data.push_back(value);} + void resize(unsigned int newSize){return m_Data.resize(newSize);} + void clear(){m_Data.clear();} + + void print(ostream & os = cout, const int level = 0) const; + + //===================================================================================== + //Operators + SignalValueType& operator[](int index){return m_Data[index];} + const SignalValueType& operator[](int index) const {return m_Data[index];} + Signal & operator/=(Signal & d); + Signal & operator*=(Signal & d); + + //Functions + Signal Normalize(double newMin=0.,double newMax=1.); + vector GetGlobalMinMax() const; + double GetGlobalMean() const; + Signal MovingAverageFilter ( unsigned int length); + Signal GaussLikeFilter (); + Signal NormalizeMeanStdDev(double newMean=0.5,double newStdDev=0.5); + Signal HighPassFilter (double sampPeriod, double cutOffFrequency ); + Signal LowPassFilter (double sampPeriod, double cutOffFrequency ); + double MaxFreq(const Signal &sig,SIGNAL_FFT_TYPE & fft); + void OneDForwardFourier(const Signal& input,SIGNAL_FFT_TYPE & fft); + void OneDBackwardFourier(SIGNAL_FFT_TYPE & fft, Signal &output); + Signal DetectLocalExtrema(unsigned int width); + Signal LimPhase(); + Signal MonPhase(); + Signal MonPhaseDE(double ee, double ei); + double SSD(const Signal &sig2) const; + Signal LinearlyInterpolateScatteredValues(); + // Signal ApproximateScatteredValuesWithBSplines (unsigned int splineOrder, unsigned int numberOfControlPoints); + Signal LimitSignalRange(); + + void AddValue(double v); + void ComputeAugmentedSpace(Signal & outputX, Signal & outputY, unsigned int delay) const; + + // double Compare(Signal & sigRef); + // int DerivateSigne( const_iterator & it) const; + // void CenteredFiniteDifferences(Signal & result,int order,int* weights); + // void FirstDerivate(Signal & result,int order); + // void SecondDerivate(Signal & result,int order); + + // void Crop(unsigned int posmin, unsigned int posmax); + // void LinearResample(const unsigned int newSize); + + + //===================================================================================== + // Get and Set function + double GetSamplingPeriod() const {return m_SamplingPeriod;} + void SetSamplingPeriod(double sp){m_SamplingPeriod=sp;} + + //===================================================================================== + //Conversion for using itk filters + Signal ConvertImageToSignal(ImageType::Pointer image); + ImageType::Pointer ConvertSignalToImage( Signal); + Signal ConvertVectorImageToSignal (VectorImageType::Pointer m); + +protected: + SignalType m_Data; + double m_SamplingPeriod; +}; +} +#endif diff --git a/common/clitkTimer.cxx b/common/clitkTimer.cxx new file mode 100644 index 0000000..85b65fd --- /dev/null +++ b/common/clitkTimer.cxx @@ -0,0 +1,81 @@ +#ifndef CLITKTIMER_CXX +#define CLITKTIMER_CXX + +/** + ================================================= + * @file clitkTimer.cxx + * @author David Sarrut + * @date 18 Jul 2007 16:27:45 + * + * @brief + * + * + =================================================*/ + +// #ifdef UNIX + +#include "clitkTimer.h" + +//==================================================================== +/// Constructs the class +clitk::Timer::Timer() { + Reset(); +} +//==================================================================== + +//==================================================================== +void clitk::Timer::Start() { + getrusage(RUSAGE_SELF, &mBegin); + mNumberOfCall++; +} +//==================================================================== + +//==================================================================== +void clitk::Timer::Stop(bool accumulate) { + getrusage(RUSAGE_SELF, &mEnd); + if (accumulate) { + mElapsed += (mEnd.ru_utime.tv_usec - mBegin.ru_utime.tv_usec)+ + (mEnd.ru_utime.tv_sec - mBegin.ru_utime.tv_sec)*1000000; + } + else { + mNumberOfCall--; + } +} +//==================================================================== + +//==================================================================== +void clitk::Timer::Print(std::ostream & os) const { + if (mNumberOfCall != 1) { + os << "Timer # = " << mNumberOfCall << std::endl; + os << "Timer total = " << mElapsed << " usec \t" << mElapsed/1000000.0 << " sec." << mElapsed/1000000.0/60 << " min." + << mElapsed/1000000.0/60/60 << " hours." << std::endl; + } + long double tus = mElapsed/mNumberOfCall; + long double ts = tus/1000000.0; + long double tm = ts/60.0; + long double th = tm/60.0; + os << "Timer = " << tus << " usec\t" << ts << " sec.\t" << tm << " min.\t" << th << " hours." << std::endl; + // os << "\tmBegin.ru_utime.tv_sec = " << mBegin.ru_utime.tv_sec << std::endl; +// os << "\tmEnd.ru_utime.tv_sec = " << mEnd.ru_utime.tv_sec << std::endl; +// os << "\tmBegin.ru_utime.tv_usec = " << mBegin.ru_utime.tv_usec << std::endl; +// os << "\tmEnd.ru_utime.tv_usec = " << mEnd.ru_utime.tv_usec << std::endl; +} +//==================================================================== + +//==================================================================== +void clitk::Timer::Print(std::string text, std::ostream & os) const { + os << text; + Print(os); +} +//==================================================================== + +//==================================================================== +void clitk::Timer::Reset() { + mNumberOfCall = 0; + mElapsed = 0; +} +//==================================================================== + +// #endif // If UNIX +#endif /* end #define CLITKTIMER_CXX */ + diff --git a/common/clitkTimer.h b/common/clitkTimer.h new file mode 100644 index 0000000..5f16a8e --- /dev/null +++ b/common/clitkTimer.h @@ -0,0 +1,53 @@ +#ifndef CLITKTIMER_H +#define CLITKTIMER_H + +/** + =================================================================== + * @file clitkTimer.h + * @author David Sarrut + * @date 18 Jul 2007 16:26:08 + + * @brief + + ===================================================================*/ + +// #ifdef UNIX + +#include "clitkCommon.h" +#include +#include +#include +#include + +namespace clitk { + + class Timer { + public: + + //==================================================================== + Timer(); + void Start(); + void Stop(bool accumulate=true); + void Reset(); + void Print(std::ostream & os=std::cout) const; + void Print(std::string text, std::ostream & os=std::cout) const; + //==================================================================== + + //==================================================================== + long double GetTimeInMicroSecond() const { return mElapsed; } + long double GetMeanTimeInMicroSecond() const { return mElapsed/mNumberOfCall; } + long int GetNumberOfCall() const { return mNumberOfCall; } + //==================================================================== + + protected: + rusage mBegin; + rusage mEnd; + long double mElapsed; + long int mNumberOfCall; + }; + +} // end namespace + +// #endif +#endif /* end #define CLITKTIMER_H */ + diff --git a/common/clitkTransformUtilities.h b/common/clitkTransformUtilities.h new file mode 100644 index 0000000..c8d100c --- /dev/null +++ b/common/clitkTransformUtilities.h @@ -0,0 +1,432 @@ +#ifndef CLITKTRANSFORMUTILITIES_H +#define CLITKTRANSFORMUTILITIES_H + +#include "itkMatrix.h" +#include "itkArray.h" +#include "itkPoint.h" +#include "clitkIOCommon.h" +#include "clitkCommon.h" + + +namespace clitk +{ + //============================================================================ + //Declarations + //============================================================================ + itk::Matrix GetForwardAffineMatrix2D(itk::Array transformParameters); + itk::Matrix GetBackwardAffineMatrix2D(itk::Array transformParameters); + itk::Matrix GetForwardAffineMatrix3D(itk::Array transformParameters); + itk::Matrix GetBackwardAffineMatrix3D(itk::Array transformParameters); + itk::Matrix GetRotationMatrix3D(itk::Array rotationParameters); + itk::Point GetRotatedPoint3D(itk::Array rotationParameters, itk::Point input); + itk::Matrix GetCenteredRotationMatrix3D(itk::Array rotationParameters,itk::Point centerOfRotation); + // itk::Matrix GetComposedMatrix3D(itk::Matrix firstTransform, itk::Matrix secondTransform); + + itk::Matrix ReadMatrix4D(std::string fileName); + itk::Matrix ReadMatrix3D(std::string fileName); + itk::Matrix ReadMatrix2D(std::string fileName); + template itk::Matrix ReadMatrix(std::string fileName); + + itk::Matrix GetRotationalPartMatrix3D(itk::Matrix input); + itk::Matrix GetRotationalPartMatrix(itk::Matrix input); + itk::Matrix GetRotationalPartMatrix2D(itk::Matrix input); + itk::Matrix GetRotationalPartMatrix(itk::Matrix input); + + itk::Vector GetTranslationPartMatrix3D(itk::Matrix input); + itk::Vector GetTranslationPartMatrix(itk::Matrix input); + itk::Vector GetTranslationPartMatrix2D(itk::Matrix input); + itk::Vector GetTranslationPartMatrix(itk::Matrix input); + + + //============================================================================ + //Inline functions definition in header file, otherwise linker errors + //============================================================================ + + //======================================================================================== + inline itk::Matrix GetForwardAffineMatrix2D(itk::Array transformParameters) + { + itk::Matrix matrix; + //rotation part + matrix[0][0]=cos(transformParameters[0]); + matrix[0][1]=-sin(transformParameters[0]); + matrix[1][0]=sin(transformParameters[0]); + matrix[1][1]=cos(transformParameters[0]); + //translation part + matrix[0][2]=transformParameters[1]; + matrix[1][2]=transformParameters[2]; + //homogenize + matrix[2][0]=0.; + matrix[2][1]=0.; + matrix[2][2]=1.; + return matrix; + } + + inline itk::Matrix GetBackwardAffineMatrix2D(itk::Array transformParameters) + { + itk::Matrix matrix; + //rotation part + matrix[0][0]=cos(transformParameters[0]); + matrix[0][1]=sin(transformParameters[0]); + matrix[1][0]=-sin(transformParameters[0]); + matrix[1][1]=cos(transformParameters[0]); + //translation part + matrix[0][2]=transformParameters[1]; + matrix[1][2]=transformParameters[2]; + //homogenize + matrix[2][0]=0.; + matrix[2][1]=0.; + matrix[2][2]=1.; + return matrix; + } + + + inline itk::Matrix GetForwardAffineMatrix3D(itk::Array transformParameters) + { + itk::Matrix matrix; + //rotational part + matrix[0][0]= cos(transformParameters[1])*cos(transformParameters[2]); + matrix[0][1]= sin(transformParameters[0])*sin(transformParameters[1])*cos(transformParameters[2])+ sin(transformParameters[2])*cos(transformParameters[0]); + matrix[0][2]= -cos(transformParameters[0])*sin(transformParameters[1])*cos(transformParameters[2])+sin(transformParameters[0])*sin(transformParameters[2]); + matrix[1][0]= -cos(transformParameters[1])*sin(transformParameters[2]); + matrix[1][1]= -sin(transformParameters[0])*sin(transformParameters[1])*sin(transformParameters[2])+cos(transformParameters[0])*cos(transformParameters[2]); + matrix[1][2]= cos(transformParameters[0])*sin(transformParameters[1])*sin(transformParameters[2])+sin(transformParameters[0])*cos(transformParameters[2]); + matrix[2][0]= sin(transformParameters[1]); + matrix[2][1]= -sin(transformParameters[0])*cos(transformParameters[1]); + matrix[2][2]= cos(transformParameters[0])*cos(transformParameters[1]); + //translational part + matrix[0][3]=transformParameters[3]; + matrix[1][3]=transformParameters[4]; + matrix[2][3]=transformParameters[5]; + //homogenize + matrix[3][0]=0.; + matrix[3][1]=0.; + matrix[3][2]=0.; + matrix[3][3]=1.; + return matrix; + } + + + inline itk::Matrix GetBackwardAffineMatrix3D(itk::Array transformParameters) + { + itk::Matrix matrix; + //rotational part + matrix[0][0]= cos(transformParameters[1])*cos(transformParameters[2]); + matrix[0][1]= sin(transformParameters[0])*sin(transformParameters[1])*cos(transformParameters[2])- sin(transformParameters[2])*cos(transformParameters[0]); + matrix[0][2]= cos(transformParameters[0])*sin(transformParameters[1])*cos(transformParameters[2])+sin(transformParameters[0])*sin(transformParameters[2]); + matrix[1][0]= cos(transformParameters[1])*sin(transformParameters[2]); + matrix[1][1]= sin(transformParameters[0])*sin(transformParameters[1])*sin(transformParameters[2])+cos(transformParameters[0])*cos(transformParameters[2]); + matrix[1][2]= cos(transformParameters[0])*sin(transformParameters[1])*sin(transformParameters[2])-sin(transformParameters[0])*cos(transformParameters[2]); + matrix[2][0]= -sin(transformParameters[1]); + matrix[2][1]= sin(transformParameters[0])*cos(transformParameters[1]); + matrix[2][2]= cos(transformParameters[0])*cos(transformParameters[1]); + //translational part + matrix[0][3]=transformParameters[3]; + matrix[1][3]=transformParameters[4]; + matrix[2][3]=transformParameters[5]; + //homogenize + matrix[3][0]=0.; + matrix[3][1]=0.; + matrix[3][2]=0.; + matrix[3][3]=1.; + return matrix; + } + + inline itk::Matrix GetRotationMatrix3D(itk::Array rotationParameters) + { + itk::Matrix matrix; + //rotational part + matrix[0][0]= cos(rotationParameters[1])*cos(rotationParameters[2]); + matrix[0][1]= sin(rotationParameters[0])*sin(rotationParameters[1])*cos(rotationParameters[2])+ sin(rotationParameters[2])*cos(rotationParameters[0]); + matrix[0][2]= -cos(rotationParameters[0])*sin(rotationParameters[1])*cos(rotationParameters[2])+sin(rotationParameters[0])*sin(rotationParameters[2]); + matrix[1][0]= -cos(rotationParameters[1])*sin(rotationParameters[2]); + matrix[1][1]= -sin(rotationParameters[0])*sin(rotationParameters[1])*sin(rotationParameters[2])+cos(rotationParameters[0])*cos(rotationParameters[2]); + matrix[1][2]= cos(rotationParameters[0])*sin(rotationParameters[1])*sin(rotationParameters[2])+sin(rotationParameters[0])*cos(rotationParameters[2]); + matrix[2][0]= sin(rotationParameters[1]); + matrix[2][1]= -sin(rotationParameters[0])*cos(rotationParameters[1]); + matrix[2][2]= cos(rotationParameters[0])*cos(rotationParameters[1]); + return matrix; + } + + + + //======================================================================================== + inline itk::Point GetRotatedPoint3D(itk::Array rotationParameters, itk::Point input) + { + itk::Matrix matrix = GetRotationMatrix3D(rotationParameters); + itk::Point output; + for (unsigned int i=0;i<3;i++) + { + output[i]=0.0; + for (unsigned int j=0;j<3;j++) + output[i]+=matrix(i,j)*input[j]; + } + return output; + } + + + inline itk::Matrix GetCenteredRotationMatrix3D(itk::Array rotationParameters,itk::Point centerOfRotation ) + { + //rotational part is identical as affine matrix, translations change + itk::Array parameters(6); + for(unsigned int i=0; i<3;i++) parameters[i]=rotationParameters[i]; + for(unsigned int i=3; i<6;i++) parameters[i]=centerOfRotation[i-3]; + itk::Matrix matrix=GetForwardAffineMatrix3D(parameters); + + //Get the rotation of the centerOfRotation + itk::Matrix rotation = GetRotationalPartMatrix3D(matrix); + itk::Point rotatedCenter=rotation*centerOfRotation; //GetRotatedPoint3D(rotationParameters, centerOfRotation); + + //Substract this point to the translational part + matrix(0,3)-=rotatedCenter[0]; + matrix(1,3)-=rotatedCenter[1]; + matrix(2,3)-=rotatedCenter[2]; + return matrix; + } + + + // inline itk::Matrix GetComposedMatrix3D(itk::Matrix firstAppliedTransform, itk::Matrix secondAppliedTransform) + // { + // itk::Matrix matrix; + // for (unsigned int i=0;i<4;i++) + // for (unsigned int j=0;j<4;j++) + // { + // matrix[i][j]=0.0; + // for (unsigned int k=0;k<4;k++) + // matrix[i][j]+=firstAppliedTransform[i][k]*secondAppliedTransform[k][j]; + // } + // return matrix; + // } + + + //======================================================================================== + inline itk::Matrix ReadMatrix4D(std::string fileName) + { + // read input matrix + std::ifstream is; + openFileForReading(is, fileName); + std::vector nb; + double x; + skipComment(is); + is >> x; + while (!is.eof()) { + nb.push_back(x); + skipComment(is); + is >> x; + } + + //copy it to the matrix + itk::Matrix matrix; + unsigned int index=0; + for (unsigned int i=0;i<5;i++) + for (unsigned int j=0;j<5;j++) + matrix[i][j]=nb[index++]; + return matrix; + } + + inline itk::Matrix ReadMatrix3D(std::string fileName) + { + // read input matrix + std::ifstream is; + openFileForReading(is, fileName); + std::vector nb; + double x; + skipComment(is); + is >> x; + while (!is.eof()) { + nb.push_back(x); + skipComment(is); + is >> x; + } + + //copy it to the matrix + itk::Matrix matrix; + unsigned int index=0; + for (unsigned int i=0;i<4;i++) + for (unsigned int j=0;j<4;j++) + matrix[i][j]=nb[index++]; + return matrix; + } + + inline itk::Matrix ReadMatrix2D(std::string fileName) + { + // read input matrix + std::ifstream is; + openFileForReading(is, fileName); + std::vector nb; + double x; + skipComment(is); + is >> x; + while (!is.eof()) { + nb.push_back(x); + skipComment(is); + is >> x; + } + + //copy it to the matrix + itk::Matrix matrix; + unsigned int index=0; + for (unsigned int i=0;i<3;i++) + for (unsigned int j=0;j<3;j++) + matrix[i][j]=nb[index++]; + return matrix; + } + + template inline itk::Matrix ReadMatrix(std::string fileName) + { + + // read input matrix + std::ifstream is; + openFileForReading(is, fileName); + std::vector nb; + double x; + skipComment(is); + is >> x; + while (!is.eof()) { + nb.push_back(x); + skipComment(is); + is >> x; + } + + //copy it to the matrix + itk::Matrix matrix; + unsigned int index=0; + for (unsigned int i=0;i inline itk::Matrix ReadMatrix<2> (std::string fileName) + // { + // return ReadMatrix2D(fileName); + // } + // template<> inline itk::Matrix ReadMatrix<3> (std::string fileName) + // { + // return ReadMatrix3D(fileName); + // } + // template<> inline itk::Matrix ReadMatrix<4> (std::string fileName) + // { + // return ReadMatrix4D(fileName); + // } + + + //======================================================================================== + inline itk::Matrix GetRotationalPartMatrix4D(itk::Matrix input) + { + itk::Matrix matrix; + matrix[0][0]= input[0][0]; + matrix[0][1]= input[0][1]; + matrix[0][2]= input[0][2]; + matrix[0][3]= input[0][3]; + matrix[1][0]= input[1][0]; + matrix[1][1]= input[1][1]; + matrix[1][2]= input[1][2]; + matrix[1][3]= input[1][3]; + matrix[2][0]= input[2][0]; + matrix[2][1]= input[2][1]; + matrix[2][2]= input[2][2]; + matrix[2][2]= input[2][2]; + matrix[2][3]= input[2][3]; + matrix[3][0]= input[3][0]; + matrix[3][1]= input[3][1]; + matrix[3][2]= input[3][2]; + matrix[3][2]= input[3][2]; + matrix[3][3]= input[3][3]; + + return matrix; + } + + + inline itk::Matrix GetRotationalPartMatrix3D(itk::Matrix input) + { + itk::Matrix matrix; + matrix[0][0]= input[0][0]; + matrix[0][1]= input[0][1]; + matrix[0][2]= input[0][2]; + matrix[1][0]= input[1][0]; + matrix[1][1]= input[1][1]; + matrix[1][2]= input[1][2]; + matrix[2][0]= input[2][0]; + matrix[2][1]= input[2][1]; + matrix[2][2]= input[2][2]; + return matrix; + } + + inline itk::Matrix GetRotationalPartMatrix2D(itk::Matrix input) + { + itk::Matrix matrix; + matrix[0][0]= input[0][0]; + matrix[0][1]= input[0][1]; + matrix[0][2]= input[0][2]; + matrix[1][0]= input[1][0]; + matrix[1][1]= input[1][1]; + return matrix; + } + + inline itk::Matrix GetRotationalPartMatrix(itk::Matrix input) + { + return GetRotationalPartMatrix4D(input); + } + + inline itk::Matrix GetRotationalPartMatrix(itk::Matrix input) + { + return GetRotationalPartMatrix3D(input); + } + + inline itk::Matrix GetRotationalPartMatrix(itk::Matrix input) + { + return GetRotationalPartMatrix2D(input); + } + + + //======================================================================================== + inline itk::Vector GetTranslationPartMatrix4D(itk::Matrix input) + { + itk::Vector vec; + vec[0]= input[0][4]; + vec[1]= input[1][4]; + vec[2]= input[2][4]; + vec[3]= input[3][4]; + return vec; + + } + + inline itk::Vector GetTranslationPartMatrix3D(itk::Matrix input) + { + itk::Vector vec; + vec[0]= input[0][3]; + vec[1]= input[1][3]; + vec[2]= input[2][3]; + return vec; + + } + inline itk::Vector GetTranslationPartMatrix2D(itk::Matrix input) + { + itk::Vector vec; + vec[0]= input[0][2]; + vec[1]= input[1][2]; + return vec; + + } + + inline itk::Vector GetTranslationPartMatrix(itk::Matrix input) + { + + return GetTranslationPartMatrix4D(input); + } + + inline itk::Vector GetTranslationPartMatrix(itk::Matrix input) + { + + return GetTranslationPartMatrix3D(input); + } + + inline itk::Vector GetTranslationPartMatrix(itk::Matrix input) + { + + return GetTranslationPartMatrix2D(input); + } +} + +#endif //#define CLITKTRANSFORMUTILITIES_H diff --git a/common/clitkVfImageIO.cxx b/common/clitkVfImageIO.cxx new file mode 100644 index 0000000..f56b13e --- /dev/null +++ b/common/clitkVfImageIO.cxx @@ -0,0 +1,211 @@ +/*========================================================================= + + Program: clitk + Module: $RCSfile: clitkVfImageIO.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:32:01 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + + +#ifndef CLITKVFIMAGEIO_CXX +#define CLITKVFIMAGEIO_CXX + +/** + * @file clitkVfImageIO.cxx + * @author Simon Rit + * @date Mon Sep 18 10:14:53 2006 + * + * @brief VectorField .vf I/O implementation + * + * + */ + +// clitk include +#include "clitkVfImageIO.h" + +// itk include (for itkReadRawBytesAfterSwappingMacro) +#include "itkRawImageIO.h" + +//==================================================================== +// Read Image Information +void clitk::VfImageIO::ReadImageInformation() +{ + // open file + std::ifstream is; + clitk::openFileForReading(is, m_FileName); + // read magic number + std::string mn; + is >> mn; + //DD(mn); + if (mn != "IAMA3DVECTORFIELD") { + itkExceptionMacro(<<"read magic number '" << mn << "' while expect IAMA3DVECTORFIELD"); + } + // read vf file version + skipComment(is); + is >> mn; + //DD(mn); + if (mn != "V2") { + itkExceptionMacro(<<"read old format '" << mn << "'. TODO"); + } + + // read grid size/spacing + itk::Vector dim; + itk::Vector spacing; + itk::Vector origin; + origin.Fill(0.0); + skipComment(is); + is >> dim[0]; + is >> dim[1]; + is >> dim[2]; + // DD(dim); + is >> spacing[0]; + is >> spacing[1]; + is >> spacing[2]; + // DD(spacing); + + // get header size + m_HeaderSize = is.tellg(); + m_HeaderSize+=2; + + // set dimension values + SetNumberOfDimensions(3); + for(unsigned int i=0; i<3; i++) { + SetDimensions(i,dim[i]); + SetSpacing(i,spacing[i]); + SetOrigin(i,origin[i]); + } + + // set other information + SetByteOrderToLittleEndian(); + SetPixelType(itk::ImageIOBase::VECTOR); + SetNumberOfComponents(3); + SetComponentType(itk::ImageIOBase::FLOAT); +} //// + +//==================================================================== +// Read Image Information +bool clitk::VfImageIO::CanReadFile(const char* FileNameToRead) +{ + std::string filename(FileNameToRead); + std::string filenameext = GetExtension(filename); + if (filenameext != std::string("vf")) return false; + return true; +} //// + +//==================================================================== +// Read Image Content +void clitk::VfImageIO::Read(void * buffer) +{ + // Adapted from itkRawImageIO + + std::ifstream file; + openFileForReading(file, m_FileName); + + // Offset into file + unsigned long streamStart = m_HeaderSize; + file.seekg((long)streamStart, std::ios::beg); + if ( file.fail() ) { + itkExceptionMacro(<<"File seek failed (Vf Read)"); + } + + float * tmpBuff = new float[GetImageSizeInComponents()]; + if(!this->ReadBufferAsBinary(file, tmpBuff, GetImageSizeInBytes())) { + itkExceptionMacro(<<"Read failed: Wanted " + << GetImageSizeInBytes() + << " bytes, but read " + << file.gcount() << " bytes."); + } + itkDebugMacro(<< "Reading Done"); + + float *pb = (float *)buffer; + float *px = tmpBuff; + float *py = tmpBuff + GetImageSizeInPixels(); + float *pz = tmpBuff + 2 * GetImageSizeInPixels(); + const float *pbe = (float *)buffer + GetImageSizeInComponents(); + while(pb != pbe){ + *pb++ = (*px++)*GetSpacing(0); + *pb++ = (*py++)*GetSpacing(1); + *pb++ = (*pz++)*GetSpacing(2); + } + delete [] tmpBuff; + + typedef itk::ByteSwapper< float > InternalByteSwapperType; + InternalByteSwapperType::SwapRangeFromSystemToLittleEndian((float *)buffer, GetImageSizeInComponents()); +} + +//==================================================================== +// Write Image Information +void clitk::VfImageIO::WriteImageInformation(bool keepOfStream) +{ + // Check dimension + if (GetNumberOfDimensions() != 3) { + itkExceptionMacro(<<"Write failed: only 3D image for Vf file format yet."); + } + + // Open the file + clitk::openFileForWriting(file, m_FileName); + // write magic number + file << "IAMA3DVECTORFIELD V2 " << std::endl; + // write grid size/spacing + file << GetDimensions(0) << ' ' + << GetDimensions(1) << ' ' + << GetDimensions(2) << ' ' + << GetSpacing(0) << ' ' + << GetSpacing(1) << ' ' + << GetSpacing(2) << ' ' << std::endl; + + // close file + if (!keepOfStream) file.close(); +} + +//==================================================================== +// Write Image Information +bool clitk::VfImageIO::CanWriteFile(const char* FileNameToWrite) +{ + std::string filename(FileNameToWrite); + std::string filenameext = GetExtension(filename); + if (filenameext != std::string("vf")) return false; + return true; +} + +//==================================================================== +// Write Image +void clitk::VfImageIO::Write(const void * buffer) +{ + clitk::VfImageIO::WriteImageInformation(true); + + typedef itk::ByteSwapper< float > InternalByteSwapperType; + std::cout << "GetImageSizeInBytes() " << GetImageSizeInBytes() << std::endl; + float* tempBuffer = new float[ GetImageSizeInPixels() ]; + + + for(int i=0 ; i< 3 ; i++){ + float *pb = (float *)buffer; + pb+=i; + float *ptb = tempBuffer; + const float *pbe = (float *)buffer + GetImageSizeInComponents() + i; + while(pb != pbe){ + *ptb++ = (*pb)/GetSpacing(i); + pb+=3; + } + InternalByteSwapperType::SwapRangeFromSystemToLittleEndian(tempBuffer,GetImageSizeInPixels()); + file.write((char*)tempBuffer, GetImageSizeInBytes()/3 ); + } + delete [] tempBuffer; + + file.close(); +} //// + +#endif /* end #define CLITKVFIMAGEIO_CXX */ + diff --git a/common/clitkVfImageIO.h b/common/clitkVfImageIO.h new file mode 100644 index 0000000..e26d7a9 --- /dev/null +++ b/common/clitkVfImageIO.h @@ -0,0 +1,66 @@ +#ifndef CLITKVFIMAGEIO_H +#define CLITKVFIMAGEIO_H + +/** + * @file clitkVfImageIO.h + * @author Simon Rit > + * @date Mon Sep 18 10:13:21 2006 + * + * @brief VectorField .vf I/O header + * + * + */ + + +// clitk include +#include "clitkCommon.h" + +// itk include +#include "itkImageIOBase.h" + +namespace clitk { + + //==================================================================== + // Class for reading Vf Image file format + class VfImageIO: public itk::ImageIOBase + { + public: + /** Standard class typedefs. */ + typedef VfImageIO Self; + typedef itk::ImageIOBase Superclass; + typedef itk::SmartPointer Pointer; + typedef signed short int PixelType; + + VfImageIO():Superclass() { mustWriteHeader = false; } + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(VfImageIO, ImageIOBase); + + /*-------- This part of the interface deals with reading data. ------ */ + virtual void ReadImageInformation(); + virtual bool CanReadFile( const char* FileNameToRead ); + virtual void Read(void * buffer); + + /*-------- This part of the interfaces deals with writing data. ----- */ + virtual void WriteImageInformation(bool keepOfStream); + virtual void WriteImageInformation() { WriteImageInformation(false); } + virtual bool CanWriteFile(const char* filename); + virtual void Write(const void* buffer); + + protected: + bool mustWriteHeader; + int m_HeaderSize; + std::ofstream file; + + }; // end class VfImageIO + +} // end namespace + + // explicit template instantiation +template class itk::CreateObjectFunction; + +#endif /* end #define CLITKVFIMAGEIO_H */ + diff --git a/common/clitkVfImageIOFactory.cxx b/common/clitkVfImageIOFactory.cxx new file mode 100644 index 0000000..c929c00 --- /dev/null +++ b/common/clitkVfImageIOFactory.cxx @@ -0,0 +1,47 @@ +/*========================================================================= + + Program: clitk + Module: $RCSfile: clitkVfImageIOFactory.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:32:01 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef CLITKVFIMAGEIOFACTORY_CXX +#define CLITKVFIMAGEIOFACTORY_CXX + +/** + * @file clitkVfImageIOFactory.cxx + * @author Simon Rit + * @date Mon Sep 18 10:14:25 2006 + * + * @brief + * + * + */ + +#include "clitkVfImageIOFactory.h" + +//==================================================================== +clitk::VfImageIOFactory::VfImageIOFactory() +{ + this->RegisterOverride("itkImageIOBase", + "VfImageIO", + "Vf Image IO", + 1, + itk::CreateObjectFunction::New()); +} + + +#endif /* end #define CLITKVFIMAGEIOFACTORY_CXX */ + diff --git a/common/clitkVfImageIOFactory.h b/common/clitkVfImageIOFactory.h new file mode 100644 index 0000000..08a0e56 --- /dev/null +++ b/common/clitkVfImageIOFactory.h @@ -0,0 +1,69 @@ +#ifndef CLITKVFIMAGEIOFACTORY_H +#define CLITKVFIMAGEIOFACTORY_H + +/** + * @file clitkVfImageIOFactory.h + * @author Simon Rit + * @date Mon Sep 18 10:14:12 2006 + * + * @brief + * + * + */ + +// clitk include +#include "clitkVfImageIO.h" + +// itk include +#include "itkImageIOBase.h" +#include "itkObjectFactoryBase.h" +#include "itkVersion.h" + +namespace clitk { + + //==================================================================== + // Factory for reading Vf Image file format + class VfImageIOFactory: public itk::ObjectFactoryBase + { + public: + /** Standard class typedefs. */ + typedef VfImageIOFactory Self; + typedef itk::ObjectFactoryBase Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Class methods used to interface with the registered factories. */ + const char* GetITKSourceVersion(void) const { + return ITK_SOURCE_VERSION; + } + + const char* GetDescription(void) const { + return "Vf ImageIO Factory, allows the loading of Vf images into insight"; + } + + /** Method for class instantiation. */ + itkFactorylessNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(VfImageIOFactory, ObjectFactoryBase); + + /** Register one factory of this type */ + static void RegisterOneFactory(void) { + ObjectFactoryBase::RegisterFactory( Self::New() ); + } + + protected: + VfImageIOFactory(); + ~VfImageIOFactory() {}; + typedef VfImageIOFactory myProductType; + const myProductType* m_MyProduct; + + private: + VfImageIOFactory(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + }; + +} // end namespace + +#endif /* end #define CLITKVFIMAGEIOFACTORY_H */ + diff --git a/common/clitkVoxImageIO.cxx b/common/clitkVoxImageIO.cxx new file mode 100644 index 0000000..aed5b04 --- /dev/null +++ b/common/clitkVoxImageIO.cxx @@ -0,0 +1,265 @@ + +/*------------------------------------------------------------------------- + + Program: clitk + Module: $RCSfile: clitkVoxImageIO.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:32:01 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + -------------------------------------------------------------------------*/ + + +#ifndef CLITKVOXIMAGEIO_CXX +#define CLITKVOXIMAGEIO_CXX + +/** + ------------------------------------------------- + * @file clitkVoxImageIO.cxx + * @author David Sarrut + * @date 17 May 2006 08:03:07 + * + * @brief + * + * + -------------------------------------------------*/ + +// clitk include +#include "clitkVoxImageIO.h" +#include "clitkCommon.h" + +// itk include (for itkReadRawBytesAfterSwappingMacro) +#include "itkRawImageIO.h" + +//-------------------------------------------------------------------- +// Read Image Information +void clitk::VoxImageIO::ReadImageInformation() { + // open file + std::ifstream is; + clitk::openFileForReading(is, m_FileName); + // read magic number + std::string mn; + is >> mn; + //DD(mn); + if (mn != "VOX") { + itkExceptionMacro(<<"read magic number '" << mn << "' while expect VOX"); + } + // read vox file version + skipComment(is); + is >> mn; + //DD(mn); + if (mn != "v2") { + itkExceptionMacro(<<"read old format '" << mn << "'. TODO"); + } + + // ONLY 3D IMAGES YET ... + + // read grid size/spacing + itk::Vector dim; + itk::Vector spacing; + itk::Vector origin; + origin.Fill(0.0); + skipComment(is); + is >> dim[0]; + is >> dim[1]; + is >> dim[2]; + //DD(dim); + skipComment(is); + is >> spacing[0]; + is >> spacing[1]; + is >> spacing[2]; + //DD(spacing); + skipComment(is); + int d; + is >> d; + if (d != 3 && d != 2) { + itkExceptionMacro(<<"could not read no " << d << "D image (only 2D and 3D). TODO"); + } + // read data type + skipComment(is); + std::string dataTypeName; + is >> dataTypeName; + //DD(dataTypeName); + + // get header size + m_HeaderSize = is.tellg(); + m_HeaderSize++; + //DD(m_HeaderSize); + + // set dimension values + SetNumberOfDimensions(d); + for(int i=0; iReadBufferAsBinary(file, buffer, numberOfBytesToBeRead)) { + itkExceptionMacro(<<"Read failed: Wanted " + << numberOfBytesToBeRead + << " bytes, but read " + << file.gcount() << " bytes."); + } + itkDebugMacro(<< "Reading Done"); + + { + using namespace itk; + // Swap bytes if necessary + if itkReadRawBytesAfterSwappingMacro( unsigned short, USHORT ) + else if itkReadRawBytesAfterSwappingMacro( short, SHORT ) + else if itkReadRawBytesAfterSwappingMacro( char, CHAR ) + else if itkReadRawBytesAfterSwappingMacro( unsigned char, UCHAR ) + else if itkReadRawBytesAfterSwappingMacro( unsigned int, UINT ) + else if itkReadRawBytesAfterSwappingMacro( int, INT ) + else if itkReadRawBytesAfterSwappingMacro( float, FLOAT ) + else if itkReadRawBytesAfterSwappingMacro( double, DOUBLE ); + } +} + +//-------------------------------------------------------------------- +// Write Image Information +void clitk::VoxImageIO::WriteImageInformation(bool keepOfStream) +{ + // Check dimension + if (GetNumberOfDimensions() != 3 && GetNumberOfDimensions() != 2) { + itkExceptionMacro(<<"Write failed: only 3D and 2D image for Vox file format yet."); + } + + // Open the file + clitk::openFileForWriting(file, m_FileName); + // write magic number + file << "VOX v2" << std::endl; + // write grid size/spacing + file << "# Size" << std::endl; + file << GetDimensions(0) << " " + << GetDimensions(1) << " " + << GetDimensions(2) << std::endl; + file << "# Spacing" << std::endl; + file.precision(40); + file << GetSpacing(0) << " " + << GetSpacing(1) << " " + << GetSpacing(2) << std::endl; + file << "# Image dim" << std::endl << "3" << std::endl; + file << "# Image type" << std::endl; + + std::string dataTypeName; + if (GetComponentType() == itk::ImageIOBase::CHAR) dataTypeName = "schar"; + else if (GetComponentType() == itk::ImageIOBase::UCHAR) dataTypeName = "uchar"; + else if (GetComponentType() == itk::ImageIOBase::SHORT) dataTypeName = "sshort"; + else if (GetComponentType() == itk::ImageIOBase::USHORT) dataTypeName = "ushort"; + else if (GetComponentType() == itk::ImageIOBase::INT) dataTypeName = "int"; + else if (GetComponentType() == itk::ImageIOBase::UINT) dataTypeName = "uint"; + else if (GetComponentType() == itk::ImageIOBase::FLOAT) dataTypeName = "float"; + else if (GetComponentType() == itk::ImageIOBase::DOUBLE) dataTypeName = "double"; + else { + itkExceptionMacro(<<"Write failed: Wanted pixel type " + << "(char, uchar, short, ushort, int, uint, float, double)" + << " but Vox is : " << dataTypeName); + } + file << dataTypeName << std::endl; + + // close file + if (!keepOfStream) file.close(); +} + +//-------------------------------------------------------------------- +// Write Image Information +bool clitk::VoxImageIO::CanWriteFile(const char* FileNameToWrite) +{ + std::string filename(FileNameToWrite); + std::string filenameext = GetExtension(filename); + if (filenameext != std::string("vox")) return false; + return true; +} + +//-------------------------------------------------------------------- +// Write Image +void clitk::VoxImageIO::Write(const void * buffer) +{ + clitk::VoxImageIO::WriteImageInformation(true); + SetByteOrderToLittleEndian(); + + //------------------------------------------- + // Cut & Paste from itkRawImageIO + // (warning BigEndian / LittleEndian) + const unsigned long numberOfBytes = this->GetImageSizeInBytes(); + const unsigned long numberOfComponents = this->GetImageSizeInComponents(); + // Swap bytes if necessary + using namespace itk; + if itkWriteRawBytesAfterSwappingMacro( unsigned short, USHORT ) + else if itkWriteRawBytesAfterSwappingMacro( short, SHORT ) + else if itkWriteRawBytesAfterSwappingMacro( char, CHAR ) + else if itkWriteRawBytesAfterSwappingMacro( unsigned char, UCHAR ) + else if itkWriteRawBytesAfterSwappingMacro( unsigned int, UINT ) + else if itkWriteRawBytesAfterSwappingMacro( int, INT ) + else if itkWriteRawBytesAfterSwappingMacro( float, FLOAT ) + else if itkWriteRawBytesAfterSwappingMacro( double, DOUBLE ) ; + //------------------------------------------- + + file.close(); +} //// + +#endif /* end #define CLITKVOXIMAGEIO_CXX */ + diff --git a/common/clitkVoxImageIO.h b/common/clitkVoxImageIO.h new file mode 100644 index 0000000..d4ffb6a --- /dev/null +++ b/common/clitkVoxImageIO.h @@ -0,0 +1,65 @@ +#ifndef CLITKVOXIMAGEIO_H +#define CLITKVOXIMAGEIO_H + +/** + =================================================================== + * @file clitkVoxImageIO.h + * @author David Sarrut + * @date 17 May 2006 08:01:35 + + * @brief + + ===================================================================*/ + +// clitk include +#include "clitkCommon.h" + +// itk include +#include "itkImageIOBase.h" + +namespace clitk { + + //==================================================================== + // Class for reading Vox Image file format + class VoxImageIO: public itk::ImageIOBase + { + public: + /** Standard class typedefs. */ + typedef VoxImageIO Self; + typedef itk::ImageIOBase Superclass; + typedef itk::SmartPointer Pointer; + typedef signed short int PixelType; + + VoxImageIO():Superclass() { mustWriteHeader = false; } + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(VoxImageIO, ImageIOBase); + + /*-------- This part of the interface deals with reading data. ------ */ + virtual void ReadImageInformation(); + virtual bool CanReadFile( const char* FileNameToRead ); + virtual void Read(void * buffer); + + /*-------- This part of the interfaces deals with writing data. ----- */ + virtual void WriteImageInformation(bool keepOfStream); + virtual void WriteImageInformation() { WriteImageInformation(false); } + virtual bool CanWriteFile(const char* filename); + virtual void Write(const void* buffer); + + protected: + bool mustWriteHeader; + int m_HeaderSize; + std::ofstream file; + + }; // end class VoxImageIO + +} // end namespace + + // explicit template instantiation +template class itk::CreateObjectFunction; + +#endif /* end #define CLITKVOXIMAGEIO_H */ + diff --git a/common/clitkVoxImageIOFactory.cxx b/common/clitkVoxImageIOFactory.cxx new file mode 100644 index 0000000..05931a1 --- /dev/null +++ b/common/clitkVoxImageIOFactory.cxx @@ -0,0 +1,48 @@ +/*========================================================================= + + Program: clitk + Module: $RCSfile: clitkVoxImageIOFactory.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:32:01 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef CLITKVOXIMAGEIOFACTORY_CXX +#define CLITKVOXIMAGEIOFACTORY_CXX + +/** + ================================================= + * @file clitkVoxImageIOFactory.cxx + * @author David Sarrut + * @date 03 Jul 2006 11:29:10 + * + * @brief + * + * + =================================================*/ + +#include "clitkVoxImageIOFactory.h" + +//==================================================================== +clitk::VoxImageIOFactory::VoxImageIOFactory() +{ + this->RegisterOverride("itkImageIOBase", + "VoxImageIO", + "Vox Image IO", + 1, + itk::CreateObjectFunction::New()); +} + + +#endif /* end #define CLITKVOXIMAGEIOFACTORY_CXX */ + diff --git a/common/clitkVoxImageIOFactory.h b/common/clitkVoxImageIOFactory.h new file mode 100644 index 0000000..81568edd --- /dev/null +++ b/common/clitkVoxImageIOFactory.h @@ -0,0 +1,69 @@ +#ifndef CLITKVOXIMAGEIOFACTORY_H +#define CLITKVOXIMAGEIOFACTORY_H + +/** + =================================================================== + * @file clitkVoxImageIOFactory.h + * @author David Sarrut + * @date 03 Jul 2006 11:27:55 + + * @brief + + ===================================================================*/ + +// clitk include +#include "clitkVoxImageIO.h" + +// itk include +#include "itkImageIOBase.h" +#include "itkObjectFactoryBase.h" +#include "itkVersion.h" + +namespace clitk { + + //==================================================================== + // Factory for reading Vox Image file format + class VoxImageIOFactory: public itk::ObjectFactoryBase + { + public: + /** Standard class typedefs. */ + typedef VoxImageIOFactory Self; + typedef itk::ObjectFactoryBase Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Class methods used to interface with the registered factories. */ + const char* GetITKSourceVersion(void) const { + return ITK_SOURCE_VERSION; + } + + const char* GetDescription(void) const { + return "Vox ImageIO Factory, allows the loading of Vox images into insight"; + } + + /** Method for class instantiation. */ + itkFactorylessNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(VoxImageIOFactory, ObjectFactoryBase); + + /** Register one factory of this type */ + static void RegisterOneFactory(void) { + ObjectFactoryBase::RegisterFactory( Self::New() ); + } + + protected: + VoxImageIOFactory(); + ~VoxImageIOFactory() {}; + typedef VoxImageIOFactory myProductType; + const myProductType* m_MyProduct; + + private: + VoxImageIOFactory(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + }; + +} // end namespace + +#endif /* end #define CLITKVOXIMAGEIOFACTORY_H */ + diff --git a/common/vvFromITK.h b/common/vvFromITK.h new file mode 100644 index 0000000..b45a2b7 --- /dev/null +++ b/common/vvFromITK.h @@ -0,0 +1,116 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvFromITK.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:32:01 $ + Version: $Revision: 1.1 $ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#ifndef vvImageFromITK_h +#define vvImageFromITK_h + +#include "vvImage.h" +#include +#include +#include "itkImageToVTKImageFilter.h" + +/**Converts the itk image to vv, handling the 4D problem + * The time_sequence boolean specifies that the image is to be interpreted as a time sequence, + * even if its dim is < 4. */ +template vvImage::Pointer vvImageFromITK(typename itk::Image::Pointer input, bool time_sequence=false) +{ + assert(Dim < 5 && Dim > 0); // We don't handle anything higher than 4-dimensional (for the moment :-p) + vvImage::Pointer vv_image=vvImage::New(); + vv_image->Init(); //Delete any existing images + typedef itk::Image< PixelType, Dim > InputImageType; + + if (Dim == 4 || time_sequence) //The time sequence case: create a series of VTK images + { + typedef itk::Image< PixelType, Dim - 1 > ConnectorImageType; + typedef itk::ImageToVTKImageFilter ConnectorType; + typedef itk::ExtractImageFilter FilterType; + + typename FilterType::Pointer filter = FilterType::New(); + typename ConnectorType::Pointer connector = ConnectorType::New(); + + //extract the 3D slices and put them in a std::vector + typename InputImageType::RegionType inputRegion = input->GetLargestPossibleRegion(); + typename InputImageType::SizeType inputSize = inputRegion.GetSize(); + + typename InputImageType::SizeType extractedRegionSize = inputSize; + typename InputImageType::RegionType extractedRegion; + extractedRegionSize[Dim - 1] = 0; + extractedRegion.SetSize(extractedRegionSize); + + filter->SetInput(input); + connector->SetInput(filter->GetOutput()); + + typename InputImageType::IndexType start = inputRegion.GetIndex(); + + for (unsigned int i = 0; i < inputSize[Dim - 1]; i++) { + start[Dim - 1] = i; + extractedRegion.SetIndex(start); + filter->SetExtractionRegion(extractedRegion); + try { + filter->Update(); + } + catch ( itk::ExceptionObject & err ) { + std::cerr << "Error while setting vvImage from ITK (Dim==4) [Extract phase]" + << " " << err << std::endl; + return vv_image; + } + try { + connector->Update(); + } + catch ( itk::ExceptionObject & err ) { + std::cerr << "Error while setting vvImage from ITK (Dim==4) [Connect phase]" + << " " << err << std::endl; + return vv_image; + } + vtkImageData *image = vtkImageData::New(); + image->DeepCopy(connector->GetOutput()); + vv_image->AddImage(image); + } + } + else //Dim == 1,2,3 and not time_sequence + { + typedef itk::Image< PixelType, Dim > ConnectorImageType; + typedef itk::ImageToVTKImageFilter ConnectorType; + typename ConnectorType::Pointer connector = ConnectorType::New(); + connector->SetInput(input); + + try { + connector->Update(); + } + catch ( itk::ExceptionObject & err ) { + std::cerr << "Error while setting vvImage from ITK (Dim==3)" + << " " << err << std::endl; + return vv_image; + } + vtkImageData *image = vtkImageData::New(); + image->DeepCopy(connector->GetOutput()); + vv_image->AddImage(image); + } + return vv_image; +} + +#endif //vvImageFromITK diff --git a/common/vvImage.cxx b/common/vvImage.cxx new file mode 100644 index 0000000..c0c3aa6 --- /dev/null +++ b/common/vvImage.cxx @@ -0,0 +1,192 @@ +#ifndef VVIMAGE_CXX +#define VVIMAGE_CXX + +/*========================================================================= + +Program: vv +Module: $RCSfile: vvImage.cxx,v $ +Language: C++ +Date: $Date: 2010/01/06 13:32:01 $ +Version: $Revision: 1.1 $ +Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#include "vvImage.h" +#include "vtkImageData.h" +#include "clitkCommon.h" +#include + +//==================================================================== +vvImage::vvImage() { + mVtkImages.resize(0); +} +//==================================================================== + +//==================================================================== +vvImage::~vvImage() { + for (unsigned int i = 0; i < mVtkImages.size(); i++) { + if (mVtkImages[i] != NULL) + mVtkImages[i]->Delete(); + } +} +//==================================================================== + +//==================================================================== +void vvImage::SetImage(std::vector images) { + for (unsigned int i = 0; i < mVtkImages.size(); i++) { + if (mVtkImages[i] != NULL) + mVtkImages[i]->Delete(); + } + mVtkImages.resize(0); + for (unsigned int i = 0; i < images.size(); i++) { + mVtkImages.push_back(images[i]); + } +} +//==================================================================== + +//==================================================================== +void vvImage::AddImage(vtkImageData* image) { + mVtkImages.push_back(image); +} +//==================================================================== + +//==================================================================== +void vvImage::Init() { + for (unsigned int i = 0; i < mVtkImages.size(); i++) { + if (mVtkImages[i] != NULL) + mVtkImages[i]->Delete(); + } + mVtkImages.resize(0); +} +//==================================================================== + +//==================================================================== +int vvImage::GetNumberOfSpatialDimensions() { + int dim=GetNumberOfDimensions(); + if (IsTimeSequence()) + return dim-1; + else + return dim; +} +//==================================================================== +// +//==================================================================== +int vvImage::GetNumberOfDimensions() const { + if (mVtkImages.size()) + { + int dimension = 2; + int extent[6]; + mVtkImages[0]->GetWholeExtent(extent); + if (extent[5] - extent[4] >= 1) + dimension++; + if (mVtkImages.size() > 1) + dimension++; + return dimension; + } + return 0; +} +//==================================================================== +void vvImage::GetScalarRange(double* range) +{ + assert(mVtkImages.size()); + double * temp = mVtkImages[0]->GetScalarRange(); + range[0]=temp[0];range[1]=temp[1]; + for (unsigned int i=1;iGetScalarRange(); + if (temp[0] < range[0]) range[0]=temp[0]; + if (temp[1] > range[1]) range[1]=temp[1]; + } +} + +//==================================================================== +std::string vvImage::GetScalarTypeAsString() { + return mVtkImages[0]->GetScalarTypeAsString(); +} +//==================================================================== + +//==================================================================== +int vvImage::GetNumberOfScalarComponents() { + return mVtkImages[0]->GetNumberOfScalarComponents(); +} +//==================================================================== + +//==================================================================== +int vvImage::GetScalarSize() { + return mVtkImages[0]->GetScalarSize(); +} +//==================================================================== + +//==================================================================== +std::vector vvImage::GetSpacing() { + std::vector spacing; + int dim = this->GetNumberOfDimensions(); + for (int i = 0; i < dim; i++) + { + if (i == 3) + spacing.push_back(1); + else + spacing.push_back(mVtkImages[0]->GetSpacing()[i]); + } + return spacing; +} +//==================================================================== + +//==================================================================== +std::vector vvImage::GetOrigin() const { + std::vector origin; + int dim = this->GetNumberOfDimensions(); + for (int i = 0; i < dim; i++) + { + if (i == 3) + origin.push_back(0); + else + origin.push_back(mVtkImages[0]->GetOrigin()[i]); + } + return origin; +} +//==================================================================== + +//==================================================================== +std::vector vvImage::GetSize() { + std::vector size0; + int dim = this->GetNumberOfDimensions(); + for (int i = 0; i < dim; i++) + { + if (i == 3) + size0.push_back(mVtkImages.size()); + else + size0.push_back(mVtkImages[0]->GetDimensions()[i]); + } + return size0; +} +//==================================================================== + +//==================================================================== +unsigned long vvImage::GetActualMemorySize() { + unsigned long size = 0; + for (unsigned int i = 0; i < mVtkImages.size(); i++) { + size += mVtkImages[i]->GetActualMemorySize(); + } + return size; +} +//==================================================================== + +#endif // VVIMAGE_CXX diff --git a/common/vvImage.h b/common/vvImage.h new file mode 100644 index 0000000..84aeae5 --- /dev/null +++ b/common/vvImage.h @@ -0,0 +1,72 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvImage.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:32:01 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvImage_h +#define vvImage_h + +#include +#include +#include + +class vtkImageData; + +class vvImage : public itk::LightObject +{ +public : + typedef vvImage Self; + typedef itk::SmartPointer Pointer; + itkNewMacro(Self); + + void Init(); + void SetImage(std::vector images); + void AddImage(vtkImageData* image); + const std::vector& GetVTKImages() { + return mVtkImages; + } + + int GetNumberOfDimensions() const; + int GetNumberOfSpatialDimensions(); + ///Writes the scalar range to the provided array, which must have room for two doubles + void GetScalarRange(double* range); + unsigned long GetActualMemorySize(); + std::vector GetSpacing(); + std::vector GetOrigin() const; + std::vector GetSize(); + std::string GetScalarTypeAsString(); + int GetNumberOfScalarComponents(); + int GetScalarSize(); + bool IsTimeSequence() { + return mVtkImages.size()>1; + } + +private: + vvImage(); + ~vvImage(); + std::vector mVtkImages; + +}; + +#endif diff --git a/common/vvToITK.h b/common/vvToITK.h new file mode 100644 index 0000000..542cea2 --- /dev/null +++ b/common/vvToITK.h @@ -0,0 +1,110 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvToITK.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:32:01 $ + Version: $Revision: 1.1 $ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvImageToITK_h +#define vvImageToITK_h + +#include +#include "vvImage.h" +#include +#include +#include "itkVTKImageToImageFilter.h" + +///Converts the vv image to itk, handling the 4D problem +template std::vector::ConstPointer> vvImageToITKImageVector(vvImage::Pointer vv_image) ///Converts the vv image to itk, handling the 4D problem +{ + assert(Dim < 5 && Dim > 1); // We don't handle anything higher than 4-dimensional (for the moment :-p) + assert(vv_image->GetVTKImages().size() > 0); //we assume there is something to convert + typedef itk::Image< PixelType, Dim > OutputImageType; + std::vector::ConstPointer> result; + + typedef itk::Image< PixelType, Dim > ConnectorImageType; + typedef itk::VTKImageToImageFilter ConnectorType; + for (unsigned int i = 0; i < vv_image->GetVTKImages().size(); i++) + { + typename ConnectorType::Pointer connector = ConnectorType::New(); + connector->SetInput(vv_image->GetVTKImages()[i]); + connector->Update(); + result.push_back(connector->GetOutput()); + } + return result; +} + +///Converts the vv image to itk, handling the 4D problem +template typename ImageType::ConstPointer vvImageToITK(vvImage::Pointer vv_image) ///Converts the vv image to itk, handling the 4D problem +{ + const unsigned int Dim=ImageType::ImageDimension; + assert(Dim < 5 && Dim > 0); // We don't handle anything higher than 4-dimensional (for the moment :-p) + typedef ImageType OutputImageType; + + if (Dim==4) + { + typedef itk::Image< typename ImageType::PixelType, 3 > ConnectorImageType; + typedef itk::VTKImageToImageFilter ConnectorType; + typedef itk::JoinSeriesImageFilter FilterType; + + + typename FilterType::Pointer filter = FilterType::New(); + filter->SetOrigin(vv_image->GetOrigin()[3]); + filter->SetSpacing(vv_image->GetSpacing()[3]); + + for (int i = 0; i < vv_image->GetSize()[3]; i++) + { + typename ConnectorType::Pointer connector = ConnectorType::New(); + connector->SetInput(vv_image->GetVTKImages()[i]); + connector->Update(); + filter->PushBackInput(connector->GetOutput()); + } + filter->Update(); + return filter->GetOutput(); + } + else //Dim == 1,2,3 + { + assert(not vv_image->IsTimeSequence()); //This case isn't implemented + typedef ImageType ConnectorImageType; + typedef itk::VTKImageToImageFilter ConnectorType; + typename ConnectorType::Pointer connector = ConnectorType::New(); + connector->SetInput(vv_image->GetVTKImages()[0]); + + connector->Update(); + return connector->GetOutput(); + } +} + +///Converts a single time frame of a vv image to itk. +template typename itk::Image::ConstPointer vvSingleFrameToITK(vvImage::Pointer vv_image,int frame) ///Converts the vv image to itk, handling the 4D problem +{ + assert(Dim < 4 && Dim > 0); + typedef itk::Image< PixelType, Dim > OutputImageType; + typedef itk::Image< PixelType, Dim > ConnectorImageType; + typedef itk::VTKImageToImageFilter ConnectorType; + typename ConnectorType::Pointer connector = ConnectorType::New(); + connector->SetInput(vv_image->GetVTKImages()[frame]); + connector->Update(); + return connector->GetOutput(); +} + +#endif diff --git a/fast_make.sh b/fast_make.sh new file mode 100755 index 0000000..471562c --- /dev/null +++ b/fast_make.sh @@ -0,0 +1,69 @@ +#!/bin/bash +vv_dir=$(dirname $(readlink -e $(which $0))) +echo vv directory: $vv_dir +cd ${vv_dir}/build + +function handle_exit +{ + rm mem_use 2>>/dev/null + killall -s SIGCONT make + killall make + killall cc1plus + echo "Terminated, exiting..." + echo + echo + exit +} + +trap handle_exit SIGINT +available_mem=$(cat /proc/meminfo | grep MemTotal | grep -o [0-9]*) +if [ -a "memory_exhausted_lock" ] +then + echo "Running in memory conservation mode..." + max_cpp_process_mem_use=1600000 + cpus=$(( $available_mem / $max_cpp_process_mem_use )) + echo "Using $cpus cpu(s) should be safe..." + sleep 1 + make -j${cpus} +else #use all the available computing power by default + cpus=$(( $(cat /proc/cpuinfo | grep -c ^processor) + 0 )) +fi + +make -j ${cpus} $@ & +make_pid=$(jobs -p %make) +#watch memory use to avoid crashes +while ps $make_pid >>/dev/null +do + if [ x"$(ps aux | grep cc1plus | grep -v grep | wc -l)" != x0 ] + then + ps ax -o vsize,comm | grep cc1plus | grep -o "\<[0-9]*\>" > mem_use + used_mem=$(awk 'BEGIN {sum=0;} {sum+=$1;} END {print sum;}' mem_use) + if (( "$used_mem"> ($available_mem - 300) )) + then + touch memory_exhausted_lock + echo "Stopping due to exagerated memory use ( $used_mem )" + handle_exit + elif (( "$used_mem"> ($available_mem/2) )) + then + if [ x$high_mem != xtrue ] + then + echo "Warning, high memory use, not spawning any more compilation jobs... ( $used_mem )" + killall -s SIGSTOP make + killall -s SIGCONT cc1plus + high_mem="true" + date_mem=$(date +%s) + fi + echo mem $used_mem / $available_mem + elif [ x$high_mem = xtrue ] && (( $(date +%s) > ( $date_mem + 5 ) )) + then + echo "Memory use back to normal" + high_mem="" + killall -s SIGCONT make + fi + rm mem_use + fi + sleep 1 +done +rm memory_exhausted_lock 2>>/dev/null +echo Done! +echo diff --git a/filters/CMakeLists.txt b/filters/CMakeLists.txt new file mode 100644 index 0000000..0172d19 --- /dev/null +++ b/filters/CMakeLists.txt @@ -0,0 +1,16 @@ +#========================================================= + +#========================================================= +# make clitk libraries + +SET( clitkFilters_SRC +clitkGuerreroVentilationGenericFilter.cxx +clitkImageArithmGenericFilter.cxx +clitkImageConvertGenericFilter.cxx +clitkImageFillRegionGenericFilter.cxx +clitkImageResampleGenericFilter.cxx +clitkSplitImageGenericFilter.cxx +clitkVFResampleGenericFilter.cxx +) + +ADD_LIBRARY(clitkFilters STATIC ${clitkFilters_SRC}) diff --git a/filters/clitkGuerreroVentilationGenericFilter.cxx b/filters/clitkGuerreroVentilationGenericFilter.cxx new file mode 100644 index 0000000..426765b --- /dev/null +++ b/filters/clitkGuerreroVentilationGenericFilter.cxx @@ -0,0 +1,97 @@ +/*========================================================================= + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +/** + ------------------------------------------------------------------- + * @file clitkGuerreroVentilationGenericFilter.cxx + * @author Joël Schaerer + * @date 20 April 2009 + + * @brief + -------------------------------------------------------------------*/ + +#include "clitkGuerreroVentilationGenericFilter.h" +#include +#include +//-------------------------------------------------------------------- +clitk::GuerreroVentilationGenericFilter::GuerreroVentilationGenericFilter() +{ + blood_mass_factor=1.; +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::GuerreroVentilationGenericFilter::Update () { + + // Determine dim, pixel type, number of components + this->GetInputImageDimensionAndPixelType(mDim,mPixelTypeName,mNbOfComponents); + + // Switch by dimension + if (mDim == 3) { Update_WithDim<3>(); return; } + if (mDim == 2) { Update_WithDim<2>(); return; } + std::cerr << "Error, dimension of input image is " << mDim << ", but I only work with 2 or 3." << std::endl; + exit(0); +} +//-------------------------------------------------------------------- + +//This is where you put the actual implementation + +#include +#include + + +//-------------------------------------------------------------------- +template +void clitk::GuerreroVentilationGenericFilter::Update_WithDim() { +#define TRY_TYPE(TYPE) \ + if (IsSameType(mPixelTypeName)) { Update_WithDimAndPixelType(); return; } + // TRY_TYPE(signed char); + // TRY_TYPE(uchar); + TRY_TYPE(short); + //TRY_TYPE(ushort); + // TRY_TYPE(int); +// TRY_TYPE(unsigned int); + //TRY_TYPE(float); + // TRY_TYPE(double); +#undef TRY_TYPE + + std::string list = CreateListOfTypes(); + std::cerr << "Error, I don't know the type '" << mPixelTypeName << "' for the input image '" + << mInputFilenames[0] << "'." << std::endl << "Known types are " << list << std::endl; + exit(0); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +void clitk::GuerreroVentilationGenericFilter::Update_WithDimAndPixelType() { + + // Read input + assert(mInputFilenames.size() == 2); + typedef itk::Image ImageType; + typedef itk::Image OutputImageType; + typename ImageType::Pointer input = clitk::readImage(mInputFilenames[0], mIOVerbose); + typename ImageType::Pointer ref = clitk::readImage(mInputFilenames[1], mIOVerbose); + + + typedef itk::BinaryGuerreroFilter GFilterType; + typename GFilterType::Pointer filter = GFilterType::New(); + filter->SetInput1(ref); + filter->SetInput2(input); + filter->SetBloodCorrectionFactor(blood_mass_factor); + filter->SetUseCorrectFormula(use_correct_formula); + filter->Update(); + this->SetNextOutput(filter->GetOutput()); + //clitk::writeImage(filter->GetOutput(), mOutputFilename, mIOVerbose); + //std::cout << "Warning: removed " << filter->GetFunctor().aberant_voxels << " aberant voxels from the ventilation image" + //<< std::endl; +} diff --git a/filters/clitkGuerreroVentilationGenericFilter.h b/filters/clitkGuerreroVentilationGenericFilter.h new file mode 100644 index 0000000..c3fd2b1 --- /dev/null +++ b/filters/clitkGuerreroVentilationGenericFilter.h @@ -0,0 +1,77 @@ +/*------------------------------------------------------------------------- + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +-------------------------------------------------------------------------*/ + +#ifndef clitkGuerreroVentilationGenericFilter_H +#define clitkGuerreroVentilationGenericFilter_H + +/** + ------------------------------------------------------------------- + * @file clitkGuerreroVentilationGenericFilter.h + * @author David Sarrut + * @date 23 Feb 2008 + -------------------------------------------------------------------*/ + +// clitk include +#include "clitkCommon.h" +#include "clitkImageCommon.h" +#include "clitkImageToImageGenericFilter.h" + +// itk include +#include "itkImage.h" +#include "itkImageIOBase.h" +#include "itkImageRegionIterator.h" +#include "itkImageRegionConstIterator.h" + +namespace clitk { + + //-------------------------------------------------------------------- + class GuerreroVentilationGenericFilter : public ImageToImageGenericFilter { + + public: + + // Constructor + GuerreroVentilationGenericFilter (); + + // Types + typedef GuerreroVentilationGenericFilter Self; + typedef ImageToImageGenericFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + // New + itkNewMacro(Self); + + // Set methods + void SetBloodCorrectionFactor(double f) {blood_mass_factor=f;} + void SetUseCorrectFormula(bool u) {use_correct_formula=u;} + + // Update + void Update (); + + protected: + //Parameters + double blood_mass_factor; + bool use_correct_formula; + + //-------------------------------------------------------------------- + template void Update_WithDim(); + template void Update_WithDimAndPixelType(); + //-------------------------------------------------------------------- + + }; // end class GuerreroVentilationGenericFilter +//-------------------------------------------------------------------- + +} // end namespace +//-------------------------------------------------------------------- + +#endif //#define clitkGuerreroVentilationGenericFilter_H + diff --git a/filters/clitkImageArithmGenericFilter.cxx b/filters/clitkImageArithmGenericFilter.cxx new file mode 100644 index 0000000..2683a93 --- /dev/null +++ b/filters/clitkImageArithmGenericFilter.cxx @@ -0,0 +1,67 @@ +/*========================================================================= + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef CLITKIMAGEARITHMGENERICFILTER_CXX +#define CLITKIMAGEARITHMGENERICFILTER_CXX + +/** + ------------------------------------------------------------------- + * @file clitkImageArithmGenericFilter.cxx + * @author David Sarrut + * @date 23 Feb 2008 + + * @brief + -------------------------------------------------------------------*/ + +#include "clitkImageArithmGenericFilter.h" + +//-------------------------------------------------------------------- +clitk::ImageArithmGenericFilter::ImageArithmGenericFilter():mTypeOfOperation(0) { + mIsOperationUseASecondImage = false; +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::ImageArithmGenericFilter::Update () { + + // Load image header + itk::ImageIOBase::Pointer header = clitk::readImageHeader(mInputFilenames[0]); + + // Determine dim, pixel type, number of components + mDim = header->GetNumberOfDimensions(); + mPixelTypeName = header->GetComponentTypeAsString(header->GetComponentType()); + mNbOfComponents = header->GetNumberOfComponents(); + + if (mInputFilenames.size() == 0) { + std::cerr << "ERROR : please provide at least a input filename." << std::endl; + } + if (mInputFilenames.size() == 1) { + mIsOperationUseASecondImage = false; + } + if (mInputFilenames.size() == 2) { + mIsOperationUseASecondImage = true; + } + if (mInputFilenames.size() > 2) { + std::cerr << "ERROR : please provide only 1 or 2 input filenames." << std::endl; + } + + // Switch by dimension + if (mDim == 2) { Update_WithDim<2>(); return; } + if (mDim == 3) { Update_WithDim<3>(); return; } + if (mDim == 4) { Update_WithDim<4>(); return; } + + std::cerr << "Error, dimension of input image is " << mDim << ", but I only work with 2,3." << std::endl; + exit(0); +} +//-------------------------------------------------------------------- + +#endif //define CLITKIMAGEARITHMGENERICFILTER_CXX diff --git a/filters/clitkImageArithmGenericFilter.h b/filters/clitkImageArithmGenericFilter.h new file mode 100644 index 0000000..8844911 --- /dev/null +++ b/filters/clitkImageArithmGenericFilter.h @@ -0,0 +1,98 @@ +/*------------------------------------------------------------------------- + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +-------------------------------------------------------------------------*/ + +#ifndef CLITKIMAGEARITHMGENERICFILTER_H +#define CLITKIMAGEARITHMGENERICFILTER_H + +/** + ------------------------------------------------------------------- + * @file clitkImageArithmGenericFilter.h + * @author David Sarrut + * @date 23 Feb 2008 08:37:53 + + * @brief + -------------------------------------------------------------------*/ + +// clitk include +#include "clitkCommon.h" +#include "clitkImageCommon.h" +#include "clitkImageToImageGenericFilter.h" + +// itk include +#include "itkImage.h" +#include "itkImageIOBase.h" +#include "itkImageRegionIterator.h" +#include "itkImageRegionConstIterator.h" + +namespace clitk { + + //-------------------------------------------------------------------- + // Main class for an Image Resample Generic Filter + // (multiple dimensions, multiple pixel types) + class ImageArithmGenericFilter : public clitk::ImageToImageGenericFilter { + + public: + + // Constructor + ImageArithmGenericFilter (); + + // Types + typedef ImageArithmGenericFilter Self; + typedef ImageToImageGenericFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + // New + itkNewMacro(Self); + + // Set methods + void SetDefaultPixelValue (double value) { mDefaultPixelValue = value ;} + void SetTypeOfOperation (int value) { mTypeOfOperation = value ;} + void SetScalar (double value) { mScalar = value ;} + + // Get methods + double GetDefaultPixelValue () { return mDefaultPixelValue ;} + int GetTypeOfOperation () { return mTypeOfOperation ;} + double GetScalar () { return mScalar ;} + + // Update + void Update (); + + protected: + bool mIsOperationUseASecondImage; + double mScalar; + double mDefaultPixelValue; + int mTypeOfOperation; + + //-------------------------------------------------------------------- + template void Update_WithDim(); + template void Update_WithDimAndPixelType(); + + template + typename ImageType::Pointer ComputeImage(typename ImageType::Pointer inputImage); + + template + typename ImageType1::Pointer + ComputeImage(typename ImageType1::Pointer inputImage1, + typename ImageType2::Pointer inputImage2); + //-------------------------------------------------------------------- + + }; // end class ImageArithmGenericFilter +//-------------------------------------------------------------------- + +#include "clitkImageArithmGenericFilter.txx" + +} // end namespace +//-------------------------------------------------------------------- + +#endif //#define CLITKIMAGEARITHMGENERICFILTER_H + diff --git a/filters/clitkImageArithmGenericFilter.txx b/filters/clitkImageArithmGenericFilter.txx new file mode 100644 index 0000000..8557dc0 --- /dev/null +++ b/filters/clitkImageArithmGenericFilter.txx @@ -0,0 +1,241 @@ +/*------------------------------------------------------------------------- + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + -------------------------------------------------------------------------*/ + +#ifndef CLITKIMAGEARITHMGENERICFILTER_TXX +#define CLITKIMAGEARITHMGENERICFILTER_TXX + +/*------------------------------------------------- + * @file clitkImageArithmGenericFilter.txx + * @author David Sarrut + * @date 9 August 2006 + * + -------------------------------------------------*/ + +//-------------------------------------------------------------------- +template +void ImageArithmGenericFilter::Update_WithDim() { +#define TRY_TYPE(TYPE) \ + if (IsSameType(mPixelTypeName)) { Update_WithDimAndPixelType(); return; } + TRY_TYPE(char); + TRY_TYPE(uchar); + TRY_TYPE(short); + TRY_TYPE(ushort); + TRY_TYPE(int); + TRY_TYPE(unsigned int); + TRY_TYPE(float); + TRY_TYPE(double); +#undef TRY_TYPE + + std::string list = CreateListOfTypes(); + std::cerr << "Error, I don't know the type '" << mPixelTypeName << "' for the input image '" + << mInputFilenames[0] << "'." << std::endl << "Known types are " << list << std::endl; + exit(0); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +void ImageArithmGenericFilter::Update_WithDimAndPixelType() { + // Read input1 + typedef itk::Image ImageType; + typename ImageType::Pointer input1 = clitk::readImage(mInputFilenames[0], mIOVerbose); + typename ImageType::Pointer outputImage; + + // Read input2 (float is ok altough it could take too memory ...) + if (mIsOperationUseASecondImage) { + typedef itk::Image ImageType2; + typename ImageType2::Pointer input2 = clitk::readImage(mInputFilenames[1], mIOVerbose); + outputImage = ComputeImage(input1, input2); + } + else { + outputImage = ComputeImage(input1); + } + + // Write results + this->SetNextOutput(outputImage); + //clitk::writeImage(outputImage, mOutputFilename, mIOVerbose); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +typename ImageType::Pointer +ImageArithmGenericFilter::ComputeImage(typename ImageType::Pointer inputImage) { + + typedef typename ImageType::PixelType PixelType; + typedef itk::ImageRegionIterator IteratorType; + IteratorType it(inputImage, inputImage->GetLargestPossibleRegion()); + it.GoToBegin(); + + switch (mTypeOfOperation) { + case 0: // Addition + while (!it.IsAtEnd()) { + it.Set(PixelTypeDownCast((double)it.Get() + mScalar) ); + ++it; + } + break; + case 1: // Multiply + while (!it.IsAtEnd()) { + it.Set(PixelTypeDownCast((double)it.Get() * mScalar) ); + ++it; + } + break; + case 2: // Inverse + while (!it.IsAtEnd()) { + if (it.Get() != 0) + it.Set(PixelTypeDownCast(mScalar / (double)it.Get())); + else it.Set(mDefaultPixelValue); + ++it; + } + break; + case 3: // Max + while (!it.IsAtEnd()) { + if (it.Get() < mScalar) it.Set(PixelTypeDownCast(mScalar)); + ++it; + } + break; + case 4: // Min + while (!it.IsAtEnd()) { + if (it.Get() > mScalar) it.Set(PixelTypeDownCast(mScalar)); + ++it; + } + break; + case 5: // Absolute value + while (!it.IsAtEnd()) { + if (it.Get() <= 0) it.Set(PixelTypeDownCast(-it.Get())); + // <= zero to avoid warning for unsigned types + ++it; + } + break; + case 6: // Squared value + while (!it.IsAtEnd()) { + it.Set(PixelTypeDownCast((double)it.Get()*(double)it.Get())); + ++it; + } + break; + case 7: // Log + while (!it.IsAtEnd()) { + if (it.Get() > 0) + it.Set(PixelTypeDownCast(log((double)it.Get()))); + else it.Set(mDefaultPixelValue); + ++it; + } + break; + case 8: // exp + while (!it.IsAtEnd()) { + it.Set(PixelTypeDownCast(exp((double)it.Get()))); + ++it; + } + break; + case 9: // sqrt + while (!it.IsAtEnd()) { + if (it.Get() > 0) + it.Set(PixelTypeDownCast(sqrt((double)it.Get()))); + else { + if (it.Get() ==0) it.Set(0); + else it.Set(mDefaultPixelValue); + } + ++it; + } + break; + default: // error ? + std::cerr << "ERROR : the operation number (" << mTypeOfOperation << ") is not known." << std::endl; + exit(-1); + } + + return inputImage; +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +typename ImageType1::Pointer +ImageArithmGenericFilter::ComputeImage(typename ImageType1::Pointer inputImage1, + typename ImageType2::Pointer inputImage2) { + + typedef typename ImageType1::PixelType PixelType; + typedef itk::ImageRegionIterator IteratorType; + IteratorType it1(inputImage1, inputImage1->GetLargestPossibleRegion()); + it1.GoToBegin(); + + typedef itk::ImageRegionConstIterator ConstIteratorType; + ConstIteratorType it2(inputImage2, inputImage2->GetLargestPossibleRegion()); + it2.GoToBegin(); + + switch (mTypeOfOperation) { + case 0: // Addition + while (!it1.IsAtEnd()) { + it1.Set(PixelTypeDownCast((double)it1.Get() + (double)it2.Get()) ); + ++it1; ++it2; + } + break; + case 1: // Multiply + while (!it1.IsAtEnd()) { + it1.Set(PixelTypeDownCast((double)it1.Get() * (double)it2.Get()) ); + ++it1; ++it2; + } + break; + case 2: // Divide + while (!it1.IsAtEnd()) { + if (it1.Get() != 0) + it1.Set(PixelTypeDownCast((double)it1.Get() / (double)it2.Get())); + else it1.Set(mDefaultPixelValue); + ++it1; ++it2; + } + break; + case 3: // Max + while (!it1.IsAtEnd()) { + if (it1.Get() < it2.Get()) it1.Set(PixelTypeDownCast(it2.Get())); + ++it1; ++it2; + } + break; + case 4: // Min + while (!it1.IsAtEnd()) { + if (it1.Get() > it2.Get()) it1.Set(PixelTypeDownCast(it2.Get())); + ++it1; ++it2; + } + break; + case 5: // Absolute difference + while (!it1.IsAtEnd()) { + it1.Set(PixelTypeDownCast(fabs(it2.Get()-it1.Get()))); + ++it1; ++it2; + } + break; + case 6: // Squared differences + while (!it1.IsAtEnd()) { + it1.Set(PixelTypeDownCast(pow((double)it1.Get()-(double)it2.Get(),2))); + ++it1; ++it2; + } + break; + case 7: // Difference + while (!it1.IsAtEnd()) { + it1.Set(PixelTypeDownCast((double)it1.Get()-(double)it2.Get())); + ++it1; ++it2; + } + break; + case 8: // Relative Difference + while (!it1.IsAtEnd()) { + if (it1.Get() != 0) it1.Set(PixelTypeDownCast(((double)it1.Get()-(double)it2.Get()))/(double)it1.Get()); + else it1.Set(0.0); + ++it1; ++it2; + } + break; + default: // error ? + std::cerr << "ERROR : the operation number (" << mTypeOfOperation << ") is not known." << std::endl; + exit(-1); + } + + return inputImage1; +} +//-------------------------------------------------------------------- + +#endif //#define CLITKIMAGEARITHMGENERICFILTER_TXX diff --git a/filters/clitkImageConvertGenericFilter.cxx b/filters/clitkImageConvertGenericFilter.cxx new file mode 100644 index 0000000..6afb8ab --- /dev/null +++ b/filters/clitkImageConvertGenericFilter.cxx @@ -0,0 +1,62 @@ +#ifndef CLITKIMAGECONVERTGENERICFILTER_CXX +#define CLITKIMAGECONVERTGENERICFILTER_CXX + +/** + ------------------------------------------------- + * @file clitkImageConvertGenericFilter.cxx + * @author David Sarrut + * @date 05 May 2008 10:57:19 + * + * @brief + * + * + -------------------------------------------------*/ + +#include "clitkImageConvertGenericFilter.h" + +//-------------------------------------------------------------------- +clitk::ImageConvertGenericFilter::ImageConvertGenericFilter():ImageToImageGenericFilter() { + mOutputPixelTypeName = "NotSpecified"; +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::ImageConvertGenericFilter::Update() { + // Load image header + itk::ImageIOBase::Pointer header = clitk::readImageHeader(mInputFilenames[0]); + + // Determine dim, pixel type, number of components + mDim = header->GetNumberOfDimensions(); + mPixelTypeName = header->GetComponentTypeAsString(header->GetComponentType()); + mNbOfComponents = header->GetNumberOfComponents(); + + // Verbose stuff + if (mIOVerbose) { + if (mInputFilenames.size() == 1) { + std::cout << "Input image <" << mInputFilenames[0] << "> is "; + printImageHeader(header, std::cout); + std::cout << std::endl; + } + else { + for(unsigned int i=0; i is "; + itk::ImageIOBase::Pointer h = clitk::readImageHeader(mInputFilenames[i]); + printImageHeader(h, std::cout); + std::cout << std::endl; + } + } + } + + // Switch by dimension + if (mInputFilenames.size() > 1) mDim++; + if (mDim == 2) { Update_WithDim<2>(); return; } + if (mDim == 3) { Update_WithDim<3>(); return; } + if (mDim == 4) { Update_WithDim<4>(); return; } + + std::cerr << "Error, dimension of input image is " << mDim << ", but I only work with 2,3,4." << std::endl; + exit(0); +} +//-------------------------------------------------------------------- + +#endif /* end #define CLITKIMAGECONVERTGENERICFILTER_CXX */ + diff --git a/filters/clitkImageConvertGenericFilter.h b/filters/clitkImageConvertGenericFilter.h new file mode 100644 index 0000000..50f80ef --- /dev/null +++ b/filters/clitkImageConvertGenericFilter.h @@ -0,0 +1,55 @@ +#ifndef CLITKIMAGECONVERTGENERICFILTER_H +#define CLITKIMAGECONVERTGENERICFILTER_H + +/** + =================================================================== + * @file clitkImageConvertGenericFilter.h + * @author David Sarrut + * @date 05 May 2008 10:40:24 + + * @brief + + ===================================================================*/ + +// clitk include +#include "clitkImageToImageGenericFilter.h" + +// itk include +#include "itkCastImageFilter.h" + +namespace clitk { + + class ImageConvertGenericFilter: public clitk::ImageToImageGenericFilter { + + public: + // constructor - destructor + ImageConvertGenericFilter(); + + // Types + typedef ImageConvertGenericFilter Self; + typedef ImageToImageGenericFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + // New + itkNewMacro(Self); + + // Members functions + void SetOutputPixelType(std::string p) { mOutputPixelTypeName = p; } + void Update(); + + protected: + std::string mOutputPixelTypeName; + + template void Update_WithDim(); + template void Update_WithDimAndPixelType(); + template void Update_WithDimAndPixelTypeAndOutputType(); + + }; // end class ImageConvertGenericFilter + +#include "clitkImageConvertGenericFilter.txx" + +} // end namespace + +#endif /* end #define CLITKIMAGECONVERTGENERICFILTER_H */ + diff --git a/filters/clitkImageConvertGenericFilter.txx b/filters/clitkImageConvertGenericFilter.txx new file mode 100644 index 0000000..28e9e2b --- /dev/null +++ b/filters/clitkImageConvertGenericFilter.txx @@ -0,0 +1,129 @@ +/*------------------------------------------------------------------------= + +Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de +l'Image). All rights reserved. See Doc/License.txt or +http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +------------------------------------------------------------------------=*/ + +#ifndef CLITKIMAGECONVERTGENERICFILTER_TXX +#define CLITKIMAGECONVERTGENERICFILTER_TXX + +/** + ================================================= + * @file clitkImageConvertGenericFilter.txx + * @author David Sarrut + * @date 05 May 2008 11:14:20 + * + * @brief + * + * + =================================================*/ + +#include + +//==================================================================== +template +void ImageConvertGenericFilter::Update_WithDim() { +#define TRY_TYPE(TYPE) \ + if (IsSameType(mPixelTypeName)) { Update_WithDimAndPixelType(); return; } + // TRY_TYPE(signed char); + TRY_TYPE(char); + TRY_TYPE(uchar); + TRY_TYPE(short); + TRY_TYPE(ushort); + TRY_TYPE(int); + TRY_TYPE(unsigned int); + TRY_TYPE(float); + TRY_TYPE(double); +#undef TRY_TYPE + + std::string list = CreateListOfTypes(); + std::cerr << "Error, I don't know the type '" << mPixelTypeName << "' for the input image '" + << mInputFilenames[0] << "'." << std::endl << "Known types are " << list << std::endl; + exit(0); +} +//==================================================================== + +//==================================================================== +template +void ImageConvertGenericFilter::Update_WithDimAndPixelType() { + if ((mPixelTypeName == mOutputPixelTypeName) || (mOutputPixelTypeName == "NotSpecified")) { + typedef itk::Image InputImageType; + typename InputImageType::Pointer input = clitk::readImage(mInputFilenames); + //clitk::writeImage(input, mOutputFilename, mIOVerbose); + this->SetNextOutput(input); + } + else { +#define TRY_TYPE(TYPE) \ + if (IsSameType(mOutputPixelTypeName)) { Update_WithDimAndPixelTypeAndOutputType(); return; } + TRY_TYPE(char); + // TRY_TYPE(signed char); + TRY_TYPE(uchar); + TRY_TYPE(short); + TRY_TYPE(ushort); + TRY_TYPE(int); // no uint ... + TRY_TYPE(float); + TRY_TYPE(double); +#undef TRY_TYPE + + std::string list = CreateListOfTypes(); + std::cerr << "Error, I don't know the output type '" << mOutputPixelTypeName + << "'. " << std::endl << "Known types are " << list << "." << std::endl; + exit(0); + } +} +//==================================================================== + +//==================================================================== +template +void ImageConvertGenericFilter::Update_WithDimAndPixelTypeAndOutputType() { + // Read + typedef itk::Image InputImageType; + typename InputImageType::Pointer input = clitk::readImage(mInputFilenames); + + // Warning + if (std::numeric_limits::is_signed) { + if (!std::numeric_limits::is_signed) { + std::cerr << "Warning, input type is signed (" << mPixelTypeName << ") while output type is not (" + << mOutputPixelTypeName << "), use at your own responsability." << std::endl; + } + } + if (!std::numeric_limits::is_integer) { + if (std::numeric_limits::is_integer) { + std::cerr << "Warning, input type is not integer (" << mPixelTypeName << ") while output type is (" + << mOutputPixelTypeName << "), use at your own responsability." << std::endl; + } + } + // DD(std::numeric_limits::digits10); + // DD(std::numeric_limits::digits10); + if (!std::numeric_limits::is_integer) { + if (std::numeric_limits::is_integer) { + std::cerr << "Warning, input type is not integer (" << mPixelTypeName << ") while output type is (" + << mOutputPixelTypeName << "), use at your own responsability." << std::endl; + } + } + if (std::numeric_limits::digits10 > std::numeric_limits::digits10) { + std::cerr << "Warning, possible loss of precision : input type is (" << mPixelTypeName << ") while output type is (" + << mOutputPixelTypeName << "), use at your own responsability." << std::endl; + } + + // Cast + typedef itk::Image OutputImageType; + typedef itk::CastImageFilter FilterType; + typename FilterType::Pointer filter = FilterType::New(); + filter->SetInput(input); + filter->Update(); + + // Write + SetNextOutput(filter->GetOutput()); + //clitk::writeImage(filter->GetOutput(), mOutputFilename, mIOVerbose); +} +//==================================================================== + +#endif /* end #define CLITKIMAGECONVERTGENERICFILTER_TXX */ + diff --git a/filters/clitkImageFillRegionGenericFilter.cxx b/filters/clitkImageFillRegionGenericFilter.cxx new file mode 100644 index 0000000..59bbff4 --- /dev/null +++ b/filters/clitkImageFillRegionGenericFilter.cxx @@ -0,0 +1,81 @@ +/*========================================================================= + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef CLITKIMAGEFILLREGIONGENERICFILTER_CXX +#define CLITKIMAGEFILLREGIONGENERICFILTER_CXX + +/** + ------------------------------------------------------------------- + * @file clitkImageFillRegionGenericFilter.cxx + * @author David Sarrut + * @date 23 Feb 2008 + + * @brief + -------------------------------------------------------------------*/ + +#include "clitkImageFillRegionGenericFilter.h" + +//-------------------------------------------------------------------- +clitk::ImageFillRegionGenericFilter::ImageFillRegionGenericFilter() { + mPixelValue = 0; + m_IsCentered=false; + mSphericRegion=false; +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +void clitk::ImageFillRegionGenericFilter::SetSphericRegion(std::vector & radius, + std::vector & center) +{ + mRadius.clear(); + mRadius.resize(radius.size()); + std::copy(radius.begin(), radius.end(), mRadius.begin()); + mCenter.clear(); + mCenter.resize(center.size()); + std::copy(center.begin(), center.end(), mCenter.begin()); + mSphericRegion = true; + m_IsCentered=false; +} + +void clitk::ImageFillRegionGenericFilter::SetSphericRegion(std::vector & radius) { + mRadius.clear(); + mRadius.resize(radius.size()); + std::copy(radius.begin(), radius.end(), mRadius.begin()); + m_IsCentered=true; + mSphericRegion = true; +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +void clitk::ImageFillRegionGenericFilter::Update () { + + // Load image header + itk::ImageIOBase::Pointer header = clitk::readImageHeader(mInputFilenames[0]); + + // Determine dim, pixel type, number of components + mDim = header->GetNumberOfDimensions(); + mPixelTypeName = header->GetComponentTypeAsString(header->GetComponentType()); + mNbOfComponents = header->GetNumberOfComponents(); + + // Switch by dimension + if (mDim == 2) { Update_WithDim<2>(); return; } + if (mDim == 3) { Update_WithDim<3>(); return; } + // if (mDim == 4) { Update_WithDim<4>(); return; } + + std::cerr << "Error, dimension of input image is " << mDim << ", but I only work with 2,3,4." << std::endl; + exit(0); +} +//-------------------------------------------------------------------- + +#endif //define CLITKIMAGEFILLREGIONGENERICFILTER_CXX diff --git a/filters/clitkImageFillRegionGenericFilter.h b/filters/clitkImageFillRegionGenericFilter.h new file mode 100644 index 0000000..ea128b9 --- /dev/null +++ b/filters/clitkImageFillRegionGenericFilter.h @@ -0,0 +1,89 @@ +/*------------------------------------------------------------------------- + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +-------------------------------------------------------------------------*/ + +#ifndef CLITKIMAGEFILLREGIONGENERICFILTER_H +#define CLITKIMAGEFILLREGIONGENERICFILTER_H + +/** + ------------------------------------------------------------------- + * @file clitkImageFillRegionGenericFilter.h + * @author David Sarrut + * @date 23 Feb 2008 + -------------------------------------------------------------------*/ + +// clitk include +#include "clitkCommon.h" +#include "clitkImageCommon.h" +#include "clitkImageToImageGenericFilter.h" + +// itk include +#include "itkImage.h" +#include "itkImageIOBase.h" +#include "itkImageRegionIterator.h" +#include "itkImageRegionConstIterator.h" +#include "itkImageRegionIteratorWithIndex.h" + +namespace clitk { + + //-------------------------------------------------------------------- + class ImageFillRegionGenericFilter : public clitk::ImageToImageGenericFilter { + + public: + + // Constructor + ImageFillRegionGenericFilter (); + ~ImageFillRegionGenericFilter (){;} + + // Types + typedef ImageFillRegionGenericFilter Self; + typedef ImageToImageGenericFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + // New + itkNewMacro(Self); + + // Set methods + void SetFillPixelValue (double value) { mPixelValue = value; } + void SetRegion(int * size, int * start) { mSize = size; mStart = start ; } + void SetSphericRegion(std::vector & radius, std::vector & center); + void SetSphericRegion(std::vector & radius); + + // Update + void Update (); + + protected: + double mPixelValue; + int * mSize; + int * mStart; + std::vector mCenter; + std::vector mRadius; + bool mSphericRegion; + bool m_IsCentered; + + + //-------------------------------------------------------------------- + template void Update_WithDim(); + template void Update_WithDimAndPixelType(); + template void Update_WithDimAndPixelType_SphericRegion(); + //-------------------------------------------------------------------- + + }; // end class ImageFillRegionGenericFilter +//-------------------------------------------------------------------- + +#include "clitkImageFillRegionGenericFilter.txx" + +} // end namespace +//-------------------------------------------------------------------- + +#endif //#define CLITKIMAGEFILLREGIONGENERICFILTER_H + diff --git a/filters/clitkImageFillRegionGenericFilter.txx b/filters/clitkImageFillRegionGenericFilter.txx new file mode 100644 index 0000000..4d81f0e --- /dev/null +++ b/filters/clitkImageFillRegionGenericFilter.txx @@ -0,0 +1,146 @@ +/*------------------------------------------------------------------------- + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + -------------------------------------------------------------------------*/ + +#ifndef CLITKIMAGEFILLREGIONGENERICFILTER_TXX +#define CLITKIMAGEFILLREGIONGENERICFILTER_TXX + +/*------------------------------------------------- + * @file clitkImageFillRegionGenericFilter.txx + * @author Cristina Gimenez + * @date 9 August 2006 + * + -------------------------------------------------*/ + +//-------------------------------------------------------------------- +template +void ImageFillRegionGenericFilter::Update_WithDim() { +#define TRY_TYPE(TYPE) \ + if (IsSameType(mPixelTypeName)) { Update_WithDimAndPixelType(); return; } + // TRY_TYPE(signed char); + // TRY_TYPE(uchar); + TRY_TYPE(short); + //TRY_TYPE(ushort); + // TRY_TYPE(int); + // TRY_TYPE(unsigned int); + TRY_TYPE(float); + // TRY_TYPE(double); +#undef TRY_TYPE + + std::string list = CreateListOfTypes(); + std::cerr << "Error, I don't know the type '" << mPixelTypeName << "' for the input image '" + << mInputFilenames[0] << "'." << std::endl << "Known types are " << list << std::endl; + exit(0); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +void ImageFillRegionGenericFilter::Update_WithDimAndPixelType() { + + // Spheric region + if (mSphericRegion) return Update_WithDimAndPixelType_SphericRegion(); + + // Read input + typedef itk::Image ImageType; + typename ImageType::Pointer input = GetInput(0); + + // Get pixel value in correct type + PixelType value = PixelTypeDownCast(mPixelValue); + + // Get region + typedef typename ImageType::RegionType RegionType; + typedef typename ImageType::SizeType SizeType; + typedef typename ImageType::IndexType IndexType; + RegionType region; + SizeType size; + IndexType start; + for(unsigned int i=0; i IteratorType; + IteratorType it(input, region); + it.GoToBegin(); + while (!it.IsAtEnd()) { + it.Set(value); + ++it; + } + + // Write results + SetNextOutput(input); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +void ImageFillRegionGenericFilter::Update_WithDimAndPixelType_SphericRegion() { + + // Read input + typedef itk::Image ImageType; + //typename ImageType::Pointer input = clitk::readImage(mInputFilenames[0], mIOVerbose); + typename ImageType::Pointer input = GetInput(0); + + // Get pixel value in correct type + PixelType value = PixelTypeDownCast(mPixelValue); + + // Centered? + if(m_IsCentered) + { + typename ImageType::SizeType size= input->GetLargestPossibleRegion().GetSize(); + typename ImageType::SpacingType spacing= input->GetSpacing(); + typename ImageType::PointType origin= input->GetOrigin(); + mCenter.resize(Dim); + for (unsigned int i=0; i IteratorType; + IteratorType it(input, input->GetLargestPossibleRegion()); + it.GoToBegin(); + + typename ImageType::PointType point; + //typename itk::Vector distance; + typename ImageType::IndexType index; + //bool inside; + double distance; + + while (!it.IsAtEnd()) + { + // inside=true; + index=it.GetIndex(); + input->TransformIndexToPhysicalPoint(index, point); + distance=0.0; + for(unsigned int i=0; i(input); +} + +//-------------------------------------------------------------------- + +#endif //#define CLITKIMAGEFILLREGIONGENERICFILTER_TXX diff --git a/filters/clitkImageResampleGenericFilter.cxx b/filters/clitkImageResampleGenericFilter.cxx new file mode 100644 index 0000000..0187e49 --- /dev/null +++ b/filters/clitkImageResampleGenericFilter.cxx @@ -0,0 +1,70 @@ +#ifndef CLITKIMAGERESAMPLEGENERICFILTER2_CXX +#define CLITKIMAGERESAMPLEGENERICFILTER2_CXX + +/** + ------------------------------------------------------------------- + * @file clitkImageResampleGenericFilter.cxx + * @author David Sarrut + * @date 23 Feb 2008 08:37:53 + + * @brief + + -------------------------------------------------------------------*/ + +#include "clitkImageResampleGenericFilter.h" + +//-------------------------------------------------------------------- +clitk::ImageResampleGenericFilter::ImageResampleGenericFilter() { + mApplyGaussianFilterBefore = false; + mDefaultPixelValue = 0.0; + mInterpolatorName = "NN"; + mBSplineOrder=3; +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::ImageResampleGenericFilter::Update() { + + // Determine dim, pixel type, number of components + this->GetInputImageDimensionAndPixelType(mDim,mPixelTypeName,mNbOfComponents); + + // Switch by dimension + if (mDim == 2) { Update_WithDim<2>(); return; } + if (mDim == 3) { Update_WithDim<3>(); return; } + if (mDim == 4) { Update_WithDim<4>(); return; } + + std::cerr << "Error, dimension of input image is " << mDim << ", but I only work with 2,3,4." << std::endl; + exit(0); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::ImageResampleGenericFilter::SetOutputSize(const std::vector & size) { + mOutputSize.resize(size.size()); + std::copy(size.begin(), size.end(), mOutputSize.begin()); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::ImageResampleGenericFilter::SetOutputSpacing(const std::vector & spacing) { + mOutputSpacing.resize(spacing.size()); + std::copy(spacing.begin(), spacing.end(), mOutputSpacing.begin()); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::ImageResampleGenericFilter::SetInterpolationName(const std::string & inter) { + mInterpolatorName = inter; +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::ImageResampleGenericFilter::SetGaussianSigma(const std::vector & sigma) { + mApplyGaussianFilterBefore = true; + mSigma.resize(sigma.size()); + std::copy(sigma.begin(), sigma.end(), mSigma.begin()); +} +//-------------------------------------------------------------------- + +#endif + diff --git a/filters/clitkImageResampleGenericFilter.h b/filters/clitkImageResampleGenericFilter.h new file mode 100644 index 0000000..d4ccc1f --- /dev/null +++ b/filters/clitkImageResampleGenericFilter.h @@ -0,0 +1,89 @@ +#ifndef CLITKIMAGERESAMPLEGENERICFILTER_H +#define CLITKIMAGERESAMPLEGENERICFILTER_H + +/** + ------------------------------------------------------------------- + * @file clitkImageResampleGenericFilter.h + * @author David Sarrut + * @date 23 Feb 2008 08:37:53 + + * @brief + -------------------------------------------------------------------*/ + +// clitk include +#include "clitkCommon.h" +#include "clitkImageCommon.h" +#include "clitkImageToImageGenericFilter.h" + +// itk include +#include "itkImage.h" +#include "itkImageFileReader.h" +#include "itkImageSeriesReader.h" +#include "itkImageFileWriter.h" +#include "itkRecursiveGaussianImageFilter.h" +#include "itkResampleImageFilter.h" +#include "itkAffineTransform.h" +#include "itkNearestNeighborInterpolateImageFunction.h" +#include "itkLinearInterpolateImageFunction.h" +#include "itkBSplineInterpolateImageFunction.h" +#include "itkBSplineInterpolateImageFunctionWithLUT.h" +#include "itkCommand.h" + +namespace clitk { + + //-------------------------------------------------------------------- + class ImageResampleGenericFilter: public clitk::ImageToImageGenericFilter { + + public: + // constructor + ImageResampleGenericFilter(); + + // Types + typedef ImageResampleGenericFilter Self; + typedef ImageToImageGenericFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + // New + itkNewMacro(Self); + + void SetOutputSize(const std::vector & size); + void SetOutputSpacing(const std::vector & spacing); + void SetGaussianSigma(const std::vector & sigma); + void SetInterpolationName(const std::string & inter); + void SetDefaultPixelValue(double dpv) { mDefaultPixelValue = dpv;} + void SetBSplineOrder(int o) { mBSplineOrder = o; } + void SetBLUTSampling(int b) { mSamplingFactors.resize(1); mSamplingFactors[0] = b; } + + void Update(); + + protected: + //-------------------------------------------------------------------- + std::string mInterpolatorName; + std::vector mOutputSize; + std::vector mOutputSpacing; + std::vector mOutputOrigin; + double mDefaultPixelValue; + bool mApplyGaussianFilterBefore; + std::vector mSigma; + int mBSplineOrder; + std::vector mSamplingFactors; + + //-------------------------------------------------------------------- + template void Update_WithDim(); + template void Update_WithDimAndPixelType(); + + //-------------------------------------------------------------------- + template + typename ImageType::Pointer ComputeImage(typename ImageType::Pointer inputImage); + + }; // end class ImageResampleGenericFilter + //-------------------------------------------------------------------- + +#include "clitkImageResampleGenericFilter.txx" + +} // end namespace +//-------------------------------------------------------------------- + +#endif /* end #define CLITKIMAGERESAMPLEGENERICFILTER_H */ + diff --git a/filters/clitkImageResampleGenericFilter.txx b/filters/clitkImageResampleGenericFilter.txx new file mode 100644 index 0000000..bdc33c0 --- /dev/null +++ b/filters/clitkImageResampleGenericFilter.txx @@ -0,0 +1,192 @@ +#ifndef CLITKIMAGERESAMPLEGENERICFILTER_TXX +#define CLITKIMAGERESAMPLEGENERICFILTER_TXX + +/** + ------------------------------------------------= + * @file clitkImageResampleGenericFilter.txx + * @author David Sarrut + * @date 23 Feb 2008 08:40:11 + * + * @brief + * + * + ------------------------------------------------=*/ + +//-------------------------------------------------------------------- +template +void ImageResampleGenericFilter::Update_WithDim() { + +#define TRY_TYPE(TYPE) \ + if (IsSameType(mPixelTypeName)) { Update_WithDimAndPixelType(); return; } + TRY_TYPE(signed char); + TRY_TYPE(uchar); + TRY_TYPE(short); + TRY_TYPE(ushort); + TRY_TYPE(int); + TRY_TYPE(unsigned int); + TRY_TYPE(float); + TRY_TYPE(double); +#undef TRY_TYPE + + std::string list = CreateListOfTypes(); + std::cerr << "Error, I don't know the type '" << mPixelTypeName << "' for the input image '" + << mInputFilenames[0] << "'." << std::endl << "Known types are " << list << std::endl; + exit(0); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +void ImageResampleGenericFilter::Update_WithDimAndPixelType() { + // Reading input + typedef itk::Image ImageType; + //typename ImageType::Pointer input = clitk::readImage(mInputFilenames, mIOVerbose); + typename ImageType::Pointer input = this->GetInput(0); + + // Main filter + typename ImageType::Pointer outputImage = ComputeImage(input); + + // Write results + this->SetNextOutput(outputImage); + //clitk::writeImage(outputImage, mOutputFilename, mIOVerbose); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +typename ImageType::Pointer +ImageResampleGenericFilter::ComputeImage(typename ImageType::Pointer inputImage) { + + // Warning + if (!std::numeric_limits::is_signed) { + if ((mInterpolatorName == "bspline") || (mInterpolatorName == "blut")) { + std::cerr << "Warning : input pixel type is not signed, use bspline interpolation at your own risk ..." << std::endl; + } + } + + // Check options + static unsigned int dim = ImageType::ImageDimension; + if (mOutputSize.size() != dim) { + std::cerr << "Please set size with " << dim << " dimensions." << std::endl; + return NULL; + } + if (mOutputSpacing.size() != dim) { + std::cerr << "Please set spacing with " << dim << " dimensions." << std::endl; + return NULL; + } + mOutputOrigin.resize(dim); + + if (mApplyGaussianFilterBefore && mSigma.size() != dim) { + std::cerr << "Please set sigma with " << dim << " dimensions." << std::endl; + return NULL; + } + + // Some typedefs + typedef typename ImageType::SizeType SizeType; + typedef typename ImageType::SpacingType SpacingType; + typedef typename ImageType::PointType PointType; + + + // Create Image Filter + typedef itk::ResampleImageFilter FilterType; + typename FilterType::Pointer filter = FilterType::New(); + + // Instance of the transform object to be passed to the resample + // filter. By default, identity transform is applied + typedef itk::AffineTransform TransformType; + typename TransformType::Pointer transform = TransformType::New(); + filter->SetTransform(transform); + + // Set filter's parameters + SizeType outputSize; + SpacingType outputSpacing; + PointType outputOrigin; + for(unsigned int i=0; iGetOrigin()[i]; + } + + filter->SetSize(outputSize); + filter->SetOutputSpacing(outputSpacing); + filter->SetOutputOrigin(outputOrigin); + filter->SetDefaultPixelValue(static_cast(mDefaultPixelValue));//DS TODO//JV comme ça? + + // Select interpolator + if (mInterpolatorName == "nn") { + typedef itk::NearestNeighborInterpolateImageFunction InterpolatorType; + typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); + filter->SetInterpolator(interpolator); + } + else { + if (mInterpolatorName == "linear") { + typedef itk::LinearInterpolateImageFunction InterpolatorType; + typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); + filter->SetInterpolator(interpolator); + } + else { + if (mInterpolatorName == "bspline") { + typedef itk::BSplineInterpolateImageFunction InterpolatorType; + typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); + interpolator->SetSplineOrder(mBSplineOrder); + filter->SetInterpolator(interpolator); + } + else { + if (mInterpolatorName == "blut") { + typedef itk::BSplineInterpolateImageFunctionWithLUT InterpolatorType; + typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); + interpolator->SetSplineOrder(mBSplineOrder); + interpolator->SetLUTSamplingFactor(mSamplingFactors[0]); + filter->SetInterpolator(interpolator); + } + else { + std::cerr << "Sorry, I do not know the interpolator '" << mInterpolatorName + << "'. Known interpolators are : nn, linear, bspline, blut" << std::endl; + exit(0); + } + } + } + } + + // Build initial Gaussian bluring (if needed) + typedef itk::RecursiveGaussianImageFilter GaussianFilterType; + std::vector gaussianFilters; + if (mApplyGaussianFilterBefore) { + for(unsigned int i=0; iSetDirection(i); + gaussianFilters[i]->SetOrder(GaussianFilterType::ZeroOrder); + gaussianFilters[i]->SetNormalizeAcrossScale(false); + gaussianFilters[i]->SetSigma(mSigma[i]); // in millimeter ! + // Set input + if (i==0) gaussianFilters[i]->SetInput(inputImage); + else gaussianFilters[i]->SetInput(gaussianFilters[i-1]->GetOutput()); + } + filter->SetInput(gaussianFilters[ImageType::ImageDimension-1]->GetOutput()); + } + else { + filter->SetInput(inputImage); + } + + // Go ! + try { + filter->Update(); + } + catch( itk::ExceptionObject & err ) { + std::cerr << "Error while filtering " << mInputFilenames[0].c_str() + << " " << err << std::endl; + exit(0); + } + + // Return result + return filter->GetOutput(); + +} +//-------------------------------------------------------------------- + + + +#endif /* end #define CLITKIMAGERESAMPLEGENERICFILTER_TXX */ + diff --git a/filters/clitkSplitImageGenericFilter.cxx b/filters/clitkSplitImageGenericFilter.cxx new file mode 100644 index 0000000..bb46dd9 --- /dev/null +++ b/filters/clitkSplitImageGenericFilter.cxx @@ -0,0 +1,49 @@ +/*========================================================================= + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +/** + ------------------------------------------------------------------- + * @file clitkSplitImageGenericFilter.cxx + * @author Joël Schaerer + * @date 20 April 2009 + + * @brief + -------------------------------------------------------------------*/ + +#include "clitkSplitImageGenericFilter.h" + +#include "clitkSplitImageGenericFilter.txx" +//-------------------------------------------------------------------- +clitk::SplitImageGenericFilter::SplitImageGenericFilter() { + mSplitDimension = 0; +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::SplitImageGenericFilter::Update () { + + // Read the Dimension and PixelType + int Dimension, Components; + std::string PixelType; + ReadImageDimensionAndPixelType(this->mInputFilenames[0], Dimension, PixelType, Components); + + + // Call UpdateWithDim + if(Dimension==3) UpdateWithDim<3>(PixelType, Components); + else if (Dimension==4)UpdateWithDim<4>(PixelType, Components); + else + { + std::cout<<"Error, Only for 3 or 4 Dimensions!!!"< + * @date 23 Feb 2008 + -------------------------------------------------------------------*/ + +// clitk include +#include "clitkCommon.h" +#include "clitkImageCommon.h" +#include "clitkImageToImageGenericFilter.h" + +// itk include +#include "itkImage.h" +#include "itkImageIOBase.h" +#include "itkImageRegionIterator.h" +#include "itkImageRegionConstIterator.h" + +namespace clitk { + + //-------------------------------------------------------------------- + class SplitImageGenericFilter : public clitk::ImageToImageGenericFilter { + + public: + + // Constructor + SplitImageGenericFilter (); + + // Types + typedef SplitImageGenericFilter Self; + typedef ImageToImageGenericFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + // New + itkNewMacro(Self); + + // Set methods + void SetSplitDimension (int dim) { mSplitDimension = dim; } + void SetVerbose (const bool v) { m_Verbose = v; } + + // Update + void Update (); + + protected: + int mSplitDimension; + bool m_Verbose; + //-------------------------------------------------------------------- + template void UpdateWithDim(std::string PixelType, int Components); + template void UpdateWithDimAndPixelType(); + //-------------------------------------------------------------------- + + }; // end class SplitImageGenericFilter +//-------------------------------------------------------------------- + +} // end namespace +//-------------------------------------------------------------------- + +#endif //#define clitkSplitImageGenericFilter_H + diff --git a/filters/clitkSplitImageGenericFilter.txx b/filters/clitkSplitImageGenericFilter.txx new file mode 100644 index 0000000..ff7a92e --- /dev/null +++ b/filters/clitkSplitImageGenericFilter.txx @@ -0,0 +1,101 @@ +/*------------------------------------------------------------------------- + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + -------------------------------------------------------------------------*/ + +#ifndef clitkSplitImageGenericFilter_TXX +#define clitkSplitImageGenericFilter_TXX + +//This is where you put the actual implementation + +#include +#include + + +//-------------------------------------------------------------------- +template +void clitk::SplitImageGenericFilter::UpdateWithDim(std::string PixelType, int Components) { + + if (m_Verbose) std::cout << "Image was detected to be "<(); + } + else if(PixelType == "unsigned_short"){ + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_short..." << std::endl; + UpdateWithDimAndPixelType(); + } + + else if (PixelType == "unsigned_char"){ + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_char..." << std::endl; + UpdateWithDimAndPixelType(); + } + + else if (PixelType == "char"){ + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed_char..." << std::endl; + UpdateWithDimAndPixelType(); + } + else { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and float..." << std::endl; + UpdateWithDimAndPixelType(); + } + } + + else if (Components==3) + { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and 3D float (DVF)" << std::endl; + UpdateWithDimAndPixelType >(); + } + else std::cerr<<"Number of components is "< +void clitk::SplitImageGenericFilter::UpdateWithDimAndPixelType() { + + // Read input + typedef itk::Image ImageType; + typedef itk::Image OutputImageType; + typename ImageType::Pointer input = clitk::readImage(mInputFilenames[0], mIOVerbose); + typedef itk::ExtractImageFilter FilterType; + typename FilterType::Pointer filter= FilterType::New(); + + filter->SetInput(input); + typename ImageType::SizeType size=input->GetLargestPossibleRegion().GetSize(); + size[mSplitDimension]=0; + typename ImageType::RegionType extracted_region; + extracted_region.SetSize(size); + filter->SetExtractionRegion(extracted_region); + filter->Update(); + + typename ImageType::IndexType index=input->GetLargestPossibleRegion().GetIndex(); + std::string base_filename=GetOutputFilename(); + unsigned int number_of_output_images=input->GetLargestPossibleRegion().GetSize()[mSplitDimension]; + for (unsigned int i=0;iSetExtractionRegion(extracted_region); + filter->Update(); + SetOutputFilename(base_filename+"_"+ss.str()+".mhd"); + typename OutputImageType::Pointer output=filter->GetOutput(); + SetNextOutput(output); + } +} +//-------------------------------------------------------------------- + +#endif //#define clitkSplitImageGenericFilter_TXX diff --git a/filters/clitkVFResampleGenericFilter.cxx b/filters/clitkVFResampleGenericFilter.cxx new file mode 100644 index 0000000..9eb995b --- /dev/null +++ b/filters/clitkVFResampleGenericFilter.cxx @@ -0,0 +1,74 @@ +#ifndef CLITKVFRESAMPLEGENERICFILTER_CXX +#define CLITKVFRESAMPLEGENERICFILTER_CXX + +/** + ------------------------------------------------------------------- + * @file clitkVFResampleGenericFilter.cxx + * @author David Sarrut + * @date 23 Feb 2008 08:37:53 + + * @brief + + -------------------------------------------------------------------*/ + +#include "clitkVFResampleGenericFilter.h" + +//-------------------------------------------------------------------- +clitk::VFResampleGenericFilter::VFResampleGenericFilter() { + mApplyGaussianFilterBefore = false; + mDefaultPixelValue = 0.0; + mInterpolatorName = "NN"; + mBSplineOrder=3; +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::VFResampleGenericFilter::Update() { + // Load image header + itk::ImageIOBase::Pointer header = clitk::readImageHeader(mInputFilenames[0]); + + // Determine dim, pixel type, number of components + mDim = header->GetNumberOfDimensions(); + mPixelTypeName = header->GetComponentTypeAsString(header->GetComponentType()); + mNbOfComponents = header->GetNumberOfComponents(); + + // Switch by dimension + if (mDim == 2) { Update_WithDim<2>(); return; } + if (mDim == 3) { Update_WithDim<3>(); return; } + if (mDim == 4) { Update_WithDim<4>(); return; } + + std::cerr << "Error, dimension of input image is " << mDim << ", but I only work with 2,3,4." << std::endl; + exit(0); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::VFResampleGenericFilter::SetOutputSize(const std::vector & size) { + mOutputSize.resize(size.size()); + std::copy(size.begin(), size.end(), mOutputSize.begin()); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::VFResampleGenericFilter::SetOutputSpacing(const std::vector & spacing) { + mOutputSpacing.resize(spacing.size()); + std::copy(spacing.begin(), spacing.end(), mOutputSpacing.begin()); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::VFResampleGenericFilter::SetInterpolationName(const std::string & inter) { + mInterpolatorName = inter; +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::VFResampleGenericFilter::SetGaussianSigma(const std::vector & sigma) { + mApplyGaussianFilterBefore = true; + mSigma.resize(sigma.size()); + std::copy(sigma.begin(), sigma.end(), mSigma.begin()); +} +//-------------------------------------------------------------------- + +#endif + diff --git a/filters/clitkVFResampleGenericFilter.h b/filters/clitkVFResampleGenericFilter.h new file mode 100644 index 0000000..b1c4568 --- /dev/null +++ b/filters/clitkVFResampleGenericFilter.h @@ -0,0 +1,93 @@ +#ifndef CLITKIMAGERESAMPLEGENERICFILTER_H +#define CLITKIMAGERESAMPLEGENERICFILTER_H + +/** + ------------------------------------------------------------------- + * @file clitkVFResampleGenericFilter.h + * @author David Sarrut + * @date 23 Feb 2008 08:37:53 + + * @brief + -------------------------------------------------------------------*/ + +// clitk include +#include "clitkCommon.h" +#include "clitkImageCommon.h" +#include "clitkImageToImageGenericFilter.h" + +// itk include +#include "itkImage.h" +#include "itkVectorImage.h" +#include "itkFixedArray.h" +#include "itkImageFileReader.h" +#include "itkImageSeriesReader.h" +#include "itkImageFileWriter.h" +#include "itkRecursiveGaussianImageFilter.h" +#include "itkVectorResampleImageFilter.h" +#include "itkAffineTransform.h" +#include "itkVectorNearestNeighborInterpolateImageFunction.h" +#include "itkVectorLinearInterpolateImageFunction.h" +#include "itkBSplineInterpolateImageFunction.h" +#include "itkBSplineInterpolateImageFunctionWithLUT.h" +#include "itkCommand.h" + +namespace clitk { + + //-------------------------------------------------------------------- + class VFResampleGenericFilter: public clitk::ImageToImageGenericFilter { + + public: + // constructor + VFResampleGenericFilter(); + + // Types + typedef VFResampleGenericFilter Self; + typedef ImageToImageGenericFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + // New + itkNewMacro(Self); + + void SetOutputSize(const std::vector & size); + void SetOutputSpacing(const std::vector & spacing); + void SetGaussianSigma(const std::vector & sigma); + void SetInterpolationName(const std::string & inter); + void SetDefaultPixelValue(double dpv) { mDefaultPixelValue = dpv;} + void SetBSplineOrder(int o) { mBSplineOrder = o; } + void SetBLUTSampling(int b) { mSamplingFactors.resize(1); mSamplingFactors[0] = b; } + + void Update(); + + protected: + //-------------------------------------------------------------------- + std::string mInterpolatorName; + std::vector mOutputSize; + std::vector mOutputSpacing; + std::vector mOutputOrigin; + double mDefaultPixelValue; + bool mApplyGaussianFilterBefore; + std::vector mSigma; + int mBSplineOrder; + std::vector mSamplingFactors; + + //-------------------------------------------------------------------- + template void Update_WithDim(); + template void Update_WithDimAndPixelType(); + template + void Update_WithDimAndPixelTypeAndComponent(); + + //-------------------------------------------------------------------- + template + typename ImageType::Pointer ComputeImage(typename ImageType::Pointer inputImage); + + }; // end class VFResampleGenericFilter + //-------------------------------------------------------------------- + +#include "clitkVFResampleGenericFilter.txx" + +} // end namespace +//-------------------------------------------------------------------- + +#endif /* end #define CLITKIMAGERESAMPLEGENERICFILTER_H */ + diff --git a/filters/clitkVFResampleGenericFilter.txx b/filters/clitkVFResampleGenericFilter.txx new file mode 100644 index 0000000..98f3c06 --- /dev/null +++ b/filters/clitkVFResampleGenericFilter.txx @@ -0,0 +1,172 @@ +#ifndef CLITKVFRESAMPLEGENERICFILTER_TXX +#define CLITKVFRESAMPLEGENERICFILTER_TXX + +/** + ------------------------------------------------= + * @file clitkVFResampleGenericFilter.txx + * @author David Sarrut + * @date 23 Feb 2008 08:40:11 + * + * @brief + * + * + ------------------------------------------------=*/ + +//-------------------------------------------------------------------- +template +void VFResampleGenericFilter::Update_WithDim() { +#define TRY_TYPE(TYPE) \ + if (IsSameType(mPixelTypeName)) { Update_WithDimAndPixelType(); return; } + TRY_TYPE(float); +#undef TRY_TYPE + std::string list = CreateListOfTypes(); + std::cerr << "Error, I don't know the type '" << mPixelTypeName << "' for the input image '" + << mInputFilenames[0] << "'." << std::endl << "Known types are " << list << std::endl; + exit(0); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +void VFResampleGenericFilter::Update_WithDimAndPixelType() { + + if (mNbOfComponents == 1) { + std::cerr << "Error, only one components ? Use clitkImageResample instead." << std::endl; + exit(0); + } + if (mNbOfComponents == 2) Update_WithDimAndPixelTypeAndComponent(); + if (mNbOfComponents == 3) Update_WithDimAndPixelTypeAndComponent(); + if (mNbOfComponents == 4) Update_WithDimAndPixelTypeAndComponent(); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +void VFResampleGenericFilter::Update_WithDimAndPixelTypeAndComponent() { + // Reading input + typedef itk::Vector DisplacementType; + typedef itk::Image< DisplacementType, Dim > ImageType; + + typename ImageType::Pointer input = clitk::readImage(mInputFilenames, mIOVerbose); + + // Main filter + typename ImageType::Pointer outputImage = ComputeImage(input); + + // Write results + SetNextOutput(outputImage); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +typename ImageType::Pointer +VFResampleGenericFilter::ComputeImage(typename ImageType::Pointer inputImage) { + + // Check options + static unsigned int dim = ImageType::ImageDimension; + if (mOutputSize.size() != dim) { + std::cerr << "Please set size with " << dim << " dimensions." << std::endl; + return NULL; + } + if (mOutputSpacing.size() != dim) { + std::cerr << "Please set spacing with " << dim << " dimensions." << std::endl; + return NULL; + } + mOutputOrigin.resize(dim); + + if (mApplyGaussianFilterBefore && mSigma.size() != dim) { + std::cerr << "Please set sigma with " << dim << " dimensions." << std::endl; + return NULL; + } + + // Some typedefs + typedef typename ImageType::SizeType SizeType; + typedef typename ImageType::SpacingType SpacingType; + typedef typename ImageType::PointType PointType; + + // Create Image Filter + typedef itk::VectorResampleImageFilter FilterType; + typename FilterType::Pointer filter = FilterType::New(); + + // Instance of the transform object to be passed to the resample + // filter. By default, identity transform is applied + typedef itk::AffineTransform TransformType; + typename TransformType::Pointer transform = TransformType::New(); + filter->SetTransform(transform); + + // Set filter's parameters + SizeType outputSize; + SpacingType outputSpacing; + PointType outputOrigin; + for(unsigned int i=0; iGetOrigin()[i]; + } + + filter->SetSize(outputSize); + filter->SetOutputSpacing(outputSpacing); + filter->SetOutputOrigin(outputOrigin); + filter->SetDefaultPixelValue(static_cast(mDefaultPixelValue)); + + // Select interpolator + if (mInterpolatorName == "nn") { + typedef itk::VectorNearestNeighborInterpolateImageFunction InterpolatorType; + typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); + filter->SetInterpolator(interpolator); + } + else { + if (mInterpolatorName == "linear") { + typedef itk::VectorLinearInterpolateImageFunction InterpolatorType; + typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); + filter->SetInterpolator(interpolator); + } + else { + std::cerr << "Sorry, I do not know the interpolator (for vector field) '" << mInterpolatorName + << "'. Known interpolators are : nn, linear" << std::endl; + exit(0); + } + } + + // Build initial Gaussian bluring (if needed) + typedef itk::RecursiveGaussianImageFilter GaussianFilterType; + std::vector gaussianFilters; + if (mApplyGaussianFilterBefore) { + for(unsigned int i=0; iSetDirection(i); + gaussianFilters[i]->SetOrder(GaussianFilterType::ZeroOrder); + gaussianFilters[i]->SetNormalizeAcrossScale(false); + gaussianFilters[i]->SetSigma(mSigma[i]); // in millimeter ! + // Set input + if (i==0) gaussianFilters[i]->SetInput(inputImage); + else gaussianFilters[i]->SetInput(gaussianFilters[i-1]->GetOutput()); + } + filter->SetInput(gaussianFilters[ImageType::ImageDimension-1]->GetOutput()); + } + else { + filter->SetInput(inputImage); + } + + // Go ! + try { + filter->Update(); + } + catch( itk::ExceptionObject & err ) { + std::cerr << "Error while filtering " << mInputFilenames[0].c_str() + << " " << err << std::endl; + exit(0); + } + + // Return result + return filter->GetOutput(); + +} +//-------------------------------------------------------------------- + + + +#endif /* end #define CLITKVFRESAMPLEGENERICFILTER_TXX */ + diff --git a/itk/clitkForwardWarpImageFilter.h b/itk/clitkForwardWarpImageFilter.h new file mode 100644 index 0000000..a02c9e5 --- /dev/null +++ b/itk/clitkForwardWarpImageFilter.h @@ -0,0 +1,106 @@ +#ifndef __clitkForwardWarpImageFilter_h +#define __clitkForwardWarpImageFilter_h + +//clitk include +#include "clitkIOCommon.h" + +//itk include +#include "itkImageToImageFilter.h" +#include "itkImage.h" +#include "itkImageRegionIterator.h" +#include "itkImageRegionIteratorWithIndex.h" +#include "itkNumericTraits.h" +#include "itkSimpleFastMutexLock.h" + +namespace clitk +{ + + template < class InputImageType, class OutputImageType, class DeformationFieldType > + class ForwardWarpImageFilter : public itk::ImageToImageFilter + + { + public: + typedef ForwardWarpImageFilter Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Determine the image dimension. */ + itkStaticConstMacro(ImageDimension, unsigned int, + InputImageType::ImageDimension ); + itkStaticConstMacro(InputImageDimension, unsigned int, + OutputImageType::ImageDimension ); + itkStaticConstMacro(DeformationFieldDimension, unsigned int, + DeformationFieldType::ImageDimension ); + + + //Some other typedefs + typedef double CoordRepType; + typedef itk::Image WeightsImageType; + typedef itk::Image MutexImageType; + + /** Point type */ + typedef itk::Point PointType; + + /** Inherit some types from the superclass. */ + typedef typename OutputImageType::IndexType IndexType; + typedef typename OutputImageType::SizeType SizeType; + typedef typename OutputImageType::PixelType PixelType; + typedef typename OutputImageType::SpacingType SpacingType; + + //Set & Get Methods (inline) + itkSetMacro( Verbose, bool); + itkSetMacro( EdgePaddingValue, PixelType ); + itkSetMacro( DeformationField, typename DeformationFieldType::Pointer); + void SetNumberOfThreads(unsigned int r ) + { + m_NumberOfThreadsIsGiven=true; + m_NumberOfThreads=r; + } + itkSetMacro(ThreadSafe, bool); + + + //ITK concept checking, why not? +#ifdef ITK_USE_CONCEPT_CHECKING + /** Begin concept checking */ + itkConceptMacro(SameDimensionCheck1, + (itk::Concept::SameDimension)); + itkConceptMacro(SameDimensionCheck2, + (itk::Concept::SameDimension)); + itkConceptMacro(InputHasNumericTraitsCheck, + (itk::Concept::HasNumericTraits)); + itkConceptMacro(DeformationFieldHasNumericTraitsCheck, + (itk::Concept::HasNumericTraits)); + /** End concept checking */ +#endif + + protected: + ForwardWarpImageFilter(); + ~ForwardWarpImageFilter() {}; + void GenerateData( ); + + + private: + bool m_Verbose; + bool m_NumberOfThreadsIsGiven; + unsigned int m_NumberOfThreads; + PixelType m_EdgePaddingValue; + typename DeformationFieldType::Pointer m_DeformationField; + bool m_ThreadSafe; + + }; + + + + + +} // end namespace clitk +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkForwardWarpImageFilter.txx" +#endif + +#endif // #define __clitkForwardWarpImageFilter_h diff --git a/itk/clitkForwardWarpImageFilter.txx b/itk/clitkForwardWarpImageFilter.txx new file mode 100644 index 0000000..9ea647e --- /dev/null +++ b/itk/clitkForwardWarpImageFilter.txx @@ -0,0 +1,499 @@ +#ifndef __clitkForwardWarpImageFilter_txx +#define __clitkForwardWarpImageFilter_txx + +#include "clitkForwardWarpImageFilter.h" +#include "clitkIOCommon.h" + +// Put the helper classes in an anonymous namespace so that it is not +// exposed to the user + +namespace +{//nameless namespace + + //========================================================================================================================= + //helper class 1 to allow a threaded execution: add contributions of input to output and update weights + //========================================================================================================================= + template class HelperClass1 : public itk::ImageToImageFilter + { + + public: + /** Standard class typedefs. */ + typedef HelperClass1 Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods) */ + itkTypeMacro( HelperClass1, ImageToImageFilter ); + + /** Constants for the image dimensions */ + itkStaticConstMacro(ImageDimension, unsigned int,InputImageType::ImageDimension); + + + //Typedefs + typedef typename OutputImageType::PixelType OutputPixelType; + typedef itk::Image WeightsImageType; + typedef itk::Image MutexImageType; + //=================================================================================== + //Set methods + void SetWeights(const typename WeightsImageType::Pointer input) + { + m_Weights = input; + this->Modified(); + } + void SetDeformationField(const typename DeformationFieldType::Pointer input) + { + m_DeformationField=input; + this->Modified(); + } + void SetMutexImage(const typename MutexImageType::Pointer input) + { + m_MutexImage=input; + this->Modified(); + m_ThreadSafe=true; + } + + //Get methods + typename WeightsImageType::Pointer GetWeights(){return m_Weights;} + + /** Typedef to describe the output image region type. */ + typedef typename OutputImageType::RegionType OutputImageRegionType; + + protected: + HelperClass1(); + ~HelperClass1(){}; + + //the actual processing + void BeforeThreadedGenerateData(); + void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId ); + + //member data + typename itk::Image< double, ImageDimension>::Pointer m_Weights; + typename DeformationFieldType::Pointer m_DeformationField; + typename MutexImageType::Pointer m_MutexImage; + bool m_ThreadSafe; + + }; + + + + //========================================================================================================================= + //Member functions of the helper class 1 + //========================================================================================================================= + + + //========================================================================================================================= + //Empty constructor + template + HelperClass1::HelperClass1() + { + m_ThreadSafe=false; + } + + + //========================================================================================================================= + //Before threaded data + template + void HelperClass1::BeforeThreadedGenerateData() + { + //Since we will add, put to zero! + this->GetOutput()->FillBuffer(itk::NumericTraits::Zero); + this->GetWeights()->FillBuffer(itk::NumericTraits::Zero); + } + + + //========================================================================================================================= + //update the output for the outputRegionForThread + template + void HelperClass1::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId ) + { + + //Get pointer to the input + typename InputImageType::ConstPointer inputPtr = this->GetInput(); + + //Get pointer to the output + typename OutputImageType::Pointer outputPtr = this->GetOutput(); + typename OutputImageType::SizeType size=outputPtr->GetLargestPossibleRegion().GetSize(); + + //Iterators over input and deformation field + typedef itk::ImageRegionConstIteratorWithIndex InputImageIteratorType; + typedef itk::ImageRegionIterator DeformationFieldIteratorType; + + //define them over the outputRegionForThread + InputImageIteratorType inputIt(inputPtr, outputRegionForThread); + DeformationFieldIteratorType fieldIt(m_DeformationField,outputRegionForThread); + + //Initialize + typename InputImageType::IndexType index; + itk::ContinuousIndex contIndex; + typename InputImageType::PointType point; + typedef typename DeformationFieldType::PixelType DisplacementType; + DisplacementType displacement; + fieldIt.GoToBegin(); + inputIt.GoToBegin(); + + //define some temp variables + signed long baseIndex[ImageDimension]; + double distance[ImageDimension]; + unsigned int dim, counter, upper; + double overlap, totalOverlap; + typename OutputImageType::IndexType neighIndex; + + //Find the number of neighbors + unsigned int neighbors = 1 << ImageDimension; + + + //================================================================================================== + //Loop over the region and add the intensities to the output and the weight to the weights + //================================================================================================== + while( !inputIt.IsAtEnd() ) + { + + // get the input image index + index = inputIt.GetIndex(); + inputPtr->TransformIndexToPhysicalPoint( index, point ); + + // get the required displacement + displacement = fieldIt.Get(); + + // compute the required output image point + for(unsigned int j = 0; j < ImageDimension; j++ ) point[j] += displacement[j]; + + + // Update the output and the weights + if(outputPtr->TransformPhysicalPointToContinuousIndex(point, contIndex ) ) + { + for(dim = 0; dim < ImageDimension; dim++) + { + // The following block is equivalent to the following line without + // having to call floor. For positive inputs!!! + // baseIndex[dim] = (long) vcl_floor(contIndex[dim] ); + baseIndex[dim] = (long) contIndex[dim]; + distance[dim] = contIndex[dim] - double( baseIndex[dim] ); + } + + //Add contribution for each neighbor + totalOverlap = itk::NumericTraits::Zero; + for( counter = 0; counter < neighbors ; counter++ ) + { + overlap = 1.0; // fraction overlap + upper = counter; // each bit indicates upper/lower neighbour + + // get neighbor index and overlap fraction + for( dim = 0; dim < 3; dim++ ) + { + if ( upper & 1 ) + { + neighIndex[dim] = baseIndex[dim] + 1; + overlap *= distance[dim]; + } + else + { + neighIndex[dim] = baseIndex[dim]; + overlap *= 1.0 - distance[dim]; + } + upper >>= 1; + } + + //Set neighbor value only if overlap is not zero + if( (overlap>0.0)) // && + // (static_cast(neighIndex[0])(neighIndex[1])(neighIndex[2])=0) && + // (neighIndex[1]>=0) && + // (neighIndex[2]>=0) ) + { + + if (! m_ThreadSafe) + { + //Set the pixel and weight at neighIndex + outputPtr->SetPixel(neighIndex, outputPtr->GetPixel(neighIndex) + overlap * static_cast(inputIt.Get())); + m_Weights->SetPixel(neighIndex, m_Weights->GetPixel(neighIndex) + overlap); + + } + else + { + //Entering critilal section: shared memory + m_MutexImage->GetPixel(neighIndex).Lock(); + + //Set the pixel and weight at neighIndex + outputPtr->SetPixel(neighIndex, outputPtr->GetPixel(neighIndex) + overlap * static_cast(inputIt.Get())); + m_Weights->SetPixel(neighIndex, m_Weights->GetPixel(neighIndex) + overlap); + + //Unlock + m_MutexImage->GetPixel(neighIndex).Unlock(); + + } + //Add to total overlap + totalOverlap += overlap; + } + + //check for totaloverlap: not very likely + if( totalOverlap == 1.0 ) + { + // finished + break; + } + } + } + + ++fieldIt; + ++inputIt; + } + + + } + + + + //========================================================================================================================= + //helper class 2 to allow a threaded execution of normalisation by the weights + //========================================================================================================================= + template + class HelperClass2 : public itk::ImageToImageFilter + { + + public: + /** Standard class typedefs. */ + typedef HelperClass2 Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods) */ + itkTypeMacro( HelperClass2, ImageToImageFilter ); + + /** Constants for the image dimensions */ + itkStaticConstMacro(ImageDimension, unsigned int,InputImageType::ImageDimension); + + //Typedefs + typedef typename InputImageType::PixelType InputPixelType; + typedef typename OutputImageType::PixelType OutputPixelType; + typedef itk::Image WeightsImageType; + + + //Set methods + void SetWeights(const typename WeightsImageType::Pointer input) + { + m_Weights = input; + this->Modified(); + } + void SetEdgePaddingValue(OutputPixelType value) + { + m_EdgePaddingValue = value; + this->Modified(); + } + + /** Typedef to describe the output image region type. */ + typedef typename OutputImageType::RegionType OutputImageRegionType; + + protected: + HelperClass2(); + ~HelperClass2(){}; + + + //the actual processing + void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId ); + + + //member data + typename WeightsImageType::Pointer m_Weights; + OutputPixelType m_EdgePaddingValue; + } ; + + + + //========================================================================================================================= + //Member functions of the helper class 2 + //========================================================================================================================= + + + //========================================================================================================================= + //Empty constructor + template + HelperClass2::HelperClass2() + { + m_EdgePaddingValue=static_cast(0.0); + } + + + //========================================================================================================================= + //update the output for the outputRegionForThread + template void + HelperClass2::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId ) + { + + //Get pointer to the input + typename InputImageType::ConstPointer inputPtr = this->GetInput(); + + //Get pointer to the output + typename OutputImageType::Pointer outputPtr = this->GetOutput(); + + //Iterators over input, weigths and output + typedef itk::ImageRegionConstIterator InputImageIteratorType; + typedef itk::ImageRegionIterator OutputImageIteratorType; + typedef itk::ImageRegionIterator WeightsImageIteratorType; + + //define them over the outputRegionForThread + OutputImageIteratorType outputIt(outputPtr, outputRegionForThread); + InputImageIteratorType inputIt(inputPtr, outputRegionForThread); + WeightsImageIteratorType weightsIt(m_Weights, outputRegionForThread); + + + //================================================================================================== + //loop over the output and normalize the input, remove holes + OutputPixelType neighValue; + double zero = itk::NumericTraits::Zero; + while (!outputIt.IsAtEnd()) + { + //the weight is not zero + if (weightsIt.Get() != zero) + { + //divide by the weight + outputIt.Set(static_cast(inputIt.Get()/weightsIt.Get())); + } + + //copy the value of the neighbour that was just processed + else + { + if(!outputIt.IsAtBegin()) + { + //go back + --outputIt; + neighValue=outputIt.Get(); + ++outputIt; + outputIt.Set(neighValue); + } + else{ + //DD("is at begin, setting edgepadding value"); + outputIt.Set(m_EdgePaddingValue); + } + } + ++weightsIt; + ++outputIt; + ++inputIt; + + }//end while + }//end member + + +}//end nameless namespace + + + +namespace clitk +{ + + //========================================================================================================================= + // The rest is the ForwardWarpImageFilter + //========================================================================================================================= + + //========================================================================================================================= + //constructor + template + ForwardWarpImageFilter::ForwardWarpImageFilter() + { + // mIsUpdated=false; + m_NumberOfThreadsIsGiven=false; + m_EdgePaddingValue=static_cast(0.0); + m_ThreadSafe=false; + m_Verbose=false; + } + + + //========================================================================================================================= + //Update + template + void ForwardWarpImageFilter::GenerateData() + { + + //Get the properties of the input + typename InputImageType::ConstPointer inputPtr=this->GetInput(); + typename WeightsImageType::RegionType region; + typename WeightsImageType::RegionType::SizeType size=inputPtr->GetLargestPossibleRegion().GetSize(); + region.SetSize(size); + typename OutputImageType::IndexType start; + for (unsigned int i =0; i< ImageDimension ;i ++)start[i]=0; + region.SetIndex(start); + + //Allocate the weights + typename WeightsImageType::Pointer weights=ForwardWarpImageFilter::WeightsImageType::New(); + weights->SetRegions(region); + weights->Allocate(); + weights->SetSpacing(inputPtr->GetSpacing()); + + + //=========================================================================== + //warp is divided in in two loops, for each we call a threaded helper class + //1. Add contribution of input to output and update weights + //2. Normalize the output by the weight and remove holes + //=========================================================================== + + //=========================================================================== + //1. Add contribution of input to output and update weights + + //Define an internal image type in double precision + typedef itk::Image InternalImageType; + + //Call threaded helper class 1 + typedef HelperClass1 HelperClass1Type; + typename HelperClass1Type::Pointer helper1=HelperClass1Type::New(); + + //Set input + if(m_NumberOfThreadsIsGiven)helper1->SetNumberOfThreads(m_NumberOfThreads); + helper1->SetInput(inputPtr); + helper1->SetDeformationField(m_DeformationField); + helper1->SetWeights(weights); + + //Threadsafe? + if(m_ThreadSafe) + { + //Allocate the mutex image + typename MutexImageType::Pointer mutex=ForwardWarpImageFilter::MutexImageType::New(); + mutex->SetRegions(region); + mutex->Allocate(); + mutex->SetSpacing(inputPtr->GetSpacing()); + helper1->SetMutexImage(mutex); + if (m_Verbose) std::cout <<"Forwarp warping using a thread-safe algorithm" <Update(); + + //Get the output + typename InternalImageType::Pointer temp= helper1->GetOutput(); + + //For clarity + weights=helper1->GetWeights(); + + + //=========================================================================== + //2. Normalize the output by the weights and remove holes + //Call threaded helper class + typedef HelperClass2 HelperClass2Type; + typename HelperClass2Type::Pointer helper2=HelperClass2Type::New(); + + //Set temporary output as input + if(m_NumberOfThreadsIsGiven)helper2->SetNumberOfThreads(m_NumberOfThreads); + helper2->SetInput(temp); + helper2->SetWeights(weights); + helper2->SetEdgePaddingValue(m_EdgePaddingValue); + + //Execute helper class + helper2->Update(); + + //Set the output + this->SetNthOutput(0, helper2->GetOutput()); + } + +} + +#endif diff --git a/itk/clitkGenericInterpolator.h b/itk/clitkGenericInterpolator.h new file mode 100644 index 0000000..4ce15f6 --- /dev/null +++ b/itk/clitkGenericInterpolator.h @@ -0,0 +1,79 @@ +#ifndef __clitkGenericInterpolator_h +#define __clitkGenericInterpolator_h + +//clitk include +#include "clitkIOCommon.h" + +//itk include +#include "itkNearestNeighborInterpolateImageFunction.h" +#include "itkLinearInterpolateImageFunction.h" +#include "itkBSplineInterpolateImageFunction.h" +#include "itkBSplineInterpolateImageFunctionWithLUT.h" + + +/* + +Requires at least the following section is the .ggo file + +option "interp" - "Interpolation: 0=NN, 1=Linear, 2=BSpline, 3=BLUT" int no default="1" +option "interpOrder" - "Order if BLUT or BSpline (0-5)" int no default="3" +option "interpSF" - "Sampling factor if BLUT" int no default="20" + +The use will something like + +typedef clitk::GenericVectorInterpolator GenericVectorInterpolatorType; +typename GenericVectorInterpolatorType::Pointer genericInterpolator=GenericVectorInterpolatorType::New(); +genericInterpolator->SetArgsInfo(m_ArgsInfo); +typedef itk::VectorInterpolateImageFunction InterpolatorType; +typename InterpolatorType::Pointer interpolator=genericInterpolator->GetInterpolatorPointer(); + +*/ + +namespace clitk +{ + + template + class GenericInterpolator : public itk::LightObject + { + public: + //============================================== + typedef GenericInterpolator Self; + typedef itk::LightObject Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + typedef itk::InterpolateImageFunction InterpolatorType; + typedef typename InterpolatorType::Pointer InterpolatorPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + //============================================== + //Set members + void SetArgsInfo(args_info_type args_info) + { + m_ArgsInfo= args_info; + m_Verbose=m_ArgsInfo.verbose_flag; + } + + //============================================== + //Get members + InterpolatorPointer GetInterpolatorPointer(void); + + //============================================== + protected: + GenericInterpolator(); + ~GenericInterpolator() {}; + + private: + args_info_type m_ArgsInfo; + InterpolatorPointer m_Interpolator; + bool m_Verbose; + }; + +} // end namespace clitk +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkGenericInterpolator.txx" +#endif + +#endif // #define __clitkGenericInterpolator_h diff --git a/itk/clitkGenericInterpolator.txx b/itk/clitkGenericInterpolator.txx new file mode 100644 index 0000000..04a8b6f --- /dev/null +++ b/itk/clitkGenericInterpolator.txx @@ -0,0 +1,75 @@ +#ifndef __clitkGenericInterpolator_txx +#define __clitkGenericInterpolator_txx + +#include "clitkGenericInterpolator.h" + + +namespace clitk +{ + + //========================================================================================================================= + //constructor + template + GenericInterpolator::GenericInterpolator() + { + m_Interpolator=NULL; + m_Verbose=false; + } + + + //========================================================================================================================= + //Get the pointer + template + typename GenericInterpolator::InterpolatorPointer + GenericInterpolator::GetInterpolatorPointer() + { + //============================================================================ + // We retrieve the type of interpolation from the command line + //============================================================================ + typename InterpolatorType::Pointer interpolator; + + switch ( m_ArgsInfo.interp_arg ) + { + case 0: + + interpolator= itk::NearestNeighborInterpolateImageFunction< ImageType,TCoordRep >::New(); + if (m_Verbose) std::cout<<"Using nearestneighbor interpolation..."<::New(); + if (m_Verbose) std::cout<<"Using linear interpolation..."<::Pointer m =itk::BSplineInterpolateImageFunction< ImageType,TCoordRep >::New(); + m->SetSplineOrder(m_ArgsInfo.interpOrder_arg); + interpolator=m; + if (m_Verbose) std::cout<<"Using Bspline interpolation..."<::Pointer m =itk::BSplineInterpolateImageFunctionWithLUT< ImageType,TCoordRep >::New(); + m->SetSplineOrder(m_ArgsInfo.interpOrder_arg); + m->SetLUTSamplingFactor(m_ArgsInfo.interpSF_arg); + interpolator=m; + if (m_Verbose) std::cout<<"Using BLUT interpolation..."< + class GenericVectorInterpolator : public itk::LightObject + { + public: + //============================================== + typedef GenericVectorInterpolator Self; + typedef itk::LightObject Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + typedef itk::VectorInterpolateImageFunction InterpolatorType; + typedef typename InterpolatorType::Pointer InterpolatorPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + //============================================== + //Set members + void SetArgsInfo(args_info_type args_info) + { + m_ArgsInfo= args_info; + m_Verbose=m_ArgsInfo.verbose_flag; + } + + //============================================== + //Get members + InterpolatorPointer GetInterpolatorPointer(void); + + //============================================== + protected: + GenericVectorInterpolator(); + ~GenericVectorInterpolator() {}; + + private: + args_info_type m_ArgsInfo; + InterpolatorPointer m_Interpolator; + bool m_Verbose; + }; + +} // end namespace clitk +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkGenericVectorInterpolator.txx" +#endif + +#endif // #define __clitkGenericVectorInterpolator_h diff --git a/itk/clitkGenericVectorInterpolator.txx b/itk/clitkGenericVectorInterpolator.txx new file mode 100644 index 0000000..639fe4f --- /dev/null +++ b/itk/clitkGenericVectorInterpolator.txx @@ -0,0 +1,74 @@ +#ifndef __clitkGenericVectorInterpolator_txx +#define __clitkGenericVectorInterpolator_txx + +#include "clitkGenericVectorInterpolator.h" + + +namespace clitk +{ + + //========================================================================================================================= + //constructor + template + GenericVectorInterpolator::GenericVectorInterpolator() + { + m_Interpolator=NULL; + m_Verbose=false; + } + + + //========================================================================================================================= + //Get the pointer + template + typename GenericVectorInterpolator::InterpolatorPointer + GenericVectorInterpolator::GetInterpolatorPointer() + { + //============================================================================ + // We retrieve the type of interpolation from the command line + //============================================================================ + typename InterpolatorType::Pointer interpolator; + + switch ( m_ArgsInfo.interpVF_arg ) + { + case 0: + + interpolator= itk::VectorNearestNeighborInterpolateImageFunction< ImageType,TCoordRep >::New(); + if (m_Verbose) std::cout<<"Using nearestneighbor interpolation..."<::New(); + if (m_Verbose) std::cout<<"Using linear interpolation..."<::Pointer m =clitk::VectorBSplineInterpolateImageFunction< ImageType,TCoordRep >::New(); + m->SetSplineOrder(m_ArgsInfo.interpVFOrder_arg); + interpolator=m; + if (m_Verbose) std::cout<<"Using Bspline interpolation..."<::Pointer m =clitk::VectorBSplineInterpolateImageFunctionWithLUT< ImageType,TCoordRep >::New(); + m->SetSplineOrder(m_ArgsInfo.interpVFOrder_arg); + m->SetLUTSamplingFactor(m_ArgsInfo.interpVFSF_arg); + interpolator=m; + if (m_Verbose) std::cout<<"Using BLUT interpolation..."< + class ITK_EXPORT InvertVFFilter : public itk::ImageToImageFilter + + { + public: + typedef InvertVFFilter Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods) */ + itkTypeMacro( InvertVFFilter, ImageToImageFilter ); + + /** Determine the image dimension. */ + itkStaticConstMacro(ImageDimension, unsigned int, + InputImageType::ImageDimension ); + + //Some other typedefs + typedef double CoordRepType; + typedef itk::Image WeightsImageType; + typedef itk::Image MutexImageType; + + /** Point type */ + typedef itk::Point PointType; + + /** Inherit some types from the superclass. */ + typedef typename OutputImageType::IndexType IndexType; + typedef typename OutputImageType::SizeType SizeType; + typedef typename OutputImageType::PixelType PixelType; + typedef typename OutputImageType::SpacingType SpacingType; + + //Set Methods(inline) + itkSetMacro( Verbose, bool); + itkSetMacro( EdgePaddingValue, PixelType ); + void SetNumberOfThreads(unsigned int r ) + { + m_NumberOfThreadsIsGiven=true; + m_NumberOfThreads=r; + } + itkSetMacro(ThreadSafe, bool); + + + protected: + InvertVFFilter(); + ~InvertVFFilter() {}; + void GenerateData( ); + + bool m_Verbose; + bool m_NumberOfThreadsIsGiven; + unsigned int m_NumberOfThreads; + PixelType m_EdgePaddingValue; + bool m_ThreadSafe; + }; + + +} // end namespace clitk +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkInvertVFFilter.txx" +#endif + +#endif // #define __clitkInvertVFFilter_h diff --git a/itk/clitkInvertVFFilter.txx b/itk/clitkInvertVFFilter.txx new file mode 100644 index 0000000..9c00cd3 --- /dev/null +++ b/itk/clitkInvertVFFilter.txx @@ -0,0 +1,483 @@ +#ifndef __clitkInvertVFFilter_txx +#define __clitkInvertVFFilter_txx + + +// Put the helper classes in an anonymous namespace so that it is not +// exposed to the user + +namespace +{ + + //========================================================================================================================= + //helper class 1 to allow a threaded execution: add contributions of input to output and update weights + //========================================================================================================================= + template class ITK_EXPORT HelperClass1 : public itk::ImageToImageFilter + { + + public: + /** Standard class typedefs. */ + typedef HelperClass1 Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods) */ + itkTypeMacro( HelperClass1, ImageToImageFilter ); + + /** Constants for the image dimensions */ + itkStaticConstMacro(ImageDimension, unsigned int,InputImageType::ImageDimension); + + + //Typedefs + typedef typename OutputImageType::PixelType PixelType; + typedef itk::Image WeightsImageType; + typedef itk::Image MutexImageType; + + //=================================================================================== + //Set methods + void SetWeights(const typename WeightsImageType::Pointer input) + { + m_Weights = input; + this->Modified(); + } + void SetMutexImage(const typename MutexImageType::Pointer input) + { + m_MutexImage=input; + this->Modified(); + m_ThreadSafe=true; + } + + //Get methods + typename WeightsImageType::Pointer GetWeights(){return m_Weights;} + + /** Typedef to describe the output image region type. */ + typedef typename OutputImageType::RegionType OutputImageRegionType; + + protected: + HelperClass1(); + ~HelperClass1(){}; + + //the actual processing + void BeforeThreadedGenerateData(); + void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId ); + + //member data + typename WeightsImageType::Pointer m_Weights; + typename MutexImageType::Pointer m_MutexImage; + bool m_ThreadSafe; + + }; + + + + //========================================================================================================================= + //Member functions of the helper class 1 + //========================================================================================================================= + + + //========================================================================================================================= + //Empty constructor + template + HelperClass1::HelperClass1() + { + m_ThreadSafe=false; + } + + //========================================================================================================================= + //Before threaded data + template + void HelperClass1::BeforeThreadedGenerateData() + { + //Since we will add, put to zero! + this->GetOutput()->FillBuffer(itk::NumericTraits::Zero); + this->GetWeights()->FillBuffer(itk::NumericTraits::Zero); + } + + //========================================================================================================================= + //update the output for the outputRegionForThread + template + void HelperClass1::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId ) + { + + //Get pointer to the input + typename InputImageType::ConstPointer inputPtr = this->GetInput(); + + //Get pointer to the output + typename OutputImageType::Pointer outputPtr = this->GetOutput(); + typename OutputImageType::SizeType size=outputPtr->GetLargestPossibleRegion().GetSize(); + + //Iterator over input + typedef itk::ImageRegionConstIteratorWithIndex InputImageIteratorType; + + //define them over the outputRegionForThread + InputImageIteratorType inputIt(inputPtr, outputRegionForThread); + + //Initialize + typename InputImageType::IndexType index; + itk::ContinuousIndex contIndex; + typename InputImageType::PointType ipoint; + typename OutputImageType::PointType opoint; + typedef typename OutputImageType::PixelType DisplacementType; + DisplacementType displacement; + inputIt.GoToBegin(); + + //define some temp variables + signed long baseIndex[ImageDimension]; + double distance[ImageDimension]; + unsigned int dim, counter, upper; + double totalOverlap,overlap; + typename OutputImageType::IndexType neighIndex; + + //Find the number of neighbors + unsigned int neighbors = 1 << ImageDimension; + + //================================================================================================== + //Loop over the region and add the intensities to the output and the weight to the weights + //================================================================================================== + while( !inputIt.IsAtEnd() ) + { + // get the input image index + index = inputIt.GetIndex(); + inputPtr->TransformIndexToPhysicalPoint( index,ipoint ); + + // get the required displacement + displacement = inputIt.Get(); + + // compute the required output image point + for(unsigned int j = 0; j < ImageDimension; j++ ) opoint[j] = ipoint[j] + (double)displacement[j]; + + // Update the output and the weights + if(outputPtr->TransformPhysicalPointToContinuousIndex(opoint, contIndex ) ) + { + for(dim = 0; dim < ImageDimension; dim++) + { + // The following block is equivalent to the following line without + // having to call floor. (Only for positive inputs, we already now that is in the image) + // baseIndex[dim] = (long) vcl_floor(contIndex[dim] ); + + baseIndex[dim] = (long) contIndex[dim]; + distance[dim] = contIndex[dim] - double( baseIndex[dim] ); + } + + //Add contribution for each neighbor + totalOverlap = itk::NumericTraits::Zero; + for( counter = 0; counter < neighbors ; counter++ ) + { + overlap = 1.0; // fraction overlap + upper = counter; // each bit indicates upper/lower neighbour + + // get neighbor index and overlap fraction + for( dim = 0; dim < 3; dim++ ) + { + if ( upper & 1 ) + { + neighIndex[dim] = baseIndex[dim] + 1; + overlap *= distance[dim]; + } + else + { + neighIndex[dim] = baseIndex[dim]; + overlap *= 1.0 - distance[dim]; + } + upper >>= 1; + } + + + + //Set neighbor value only if overlap is not zero + if( (overlap>0.0)) // && + // (static_cast(neighIndex[0])(neighIndex[1])(neighIndex[2])=0) && + // (neighIndex[1]>=0) && + // (neighIndex[2]>=0) ) + { + //what to store? the original displacement vector? + if (! m_ThreadSafe) + { + //Set the pixel and weight at neighIndex + outputPtr->SetPixel(neighIndex, outputPtr->GetPixel(neighIndex) - (displacement*overlap)); + m_Weights->SetPixel(neighIndex, m_Weights->GetPixel(neighIndex) + overlap); + } + + else + { + //Entering critilal section: shared memory + m_MutexImage->GetPixel(neighIndex).Lock(); + + //Set the pixel and weight at neighIndex + outputPtr->SetPixel(neighIndex, outputPtr->GetPixel(neighIndex) - (displacement*overlap)); + m_Weights->SetPixel(neighIndex, m_Weights->GetPixel(neighIndex) + overlap); + + //Unlock + m_MutexImage->GetPixel(neighIndex).Unlock(); + + } + //Add to total overlap + totalOverlap += overlap; + } + + if( totalOverlap == 1.0 ) + { + // finished + break; + } + } + } + + ++inputIt; + } + + } + + + + //========================================================================================================================= + //helper class 2 to allow a threaded execution of normalisation by the weights + //========================================================================================================================= + template class HelperClass2 : public itk::ImageToImageFilter + { + + public: + /** Standard class typedefs. */ + typedef HelperClass2 Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods) */ + itkTypeMacro( HelperClass2, ImageToImageFilter ); + + /** Constants for the image dimensions */ + itkStaticConstMacro(ImageDimension, unsigned int,InputImageType::ImageDimension); + + //Typedefs + typedef typename OutputImageType::PixelType PixelType; + typedef itk::Image WeightsImageType; + + //Set methods + void SetWeights(const typename WeightsImageType::Pointer input) + { + m_Weights = input; + this->Modified(); + } + void SetEdgePaddingValue(PixelType value) + { + m_EdgePaddingValue = value; + this->Modified(); + } + + /** Typedef to describe the output image region type. */ + typedef typename OutputImageType::RegionType OutputImageRegionType; + + protected: + HelperClass2(); + ~HelperClass2(){}; + + + //the actual processing + void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId ); + + + //member data + typename WeightsImageType::Pointer m_Weights; + PixelType m_EdgePaddingValue; + + } ; + + + + //========================================================================================================================= + //Member functions of the helper class 2 + //========================================================================================================================= + + + //========================================================================================================================= + //Empty constructor + template HelperClass2::HelperClass2() + { + m_EdgePaddingValue=itk::NumericTraits::Zero; + } + + + //========================================================================================================================= + //update the output for the outputRegionForThread + template void HelperClass2::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId ) + { + + //Get pointer to the input + typename InputImageType::ConstPointer inputPtr = this->GetInput(); + + //Get pointer to the output + typename OutputImageType::Pointer outputPtr = this->GetOutput(); + + //Iterators over input, weigths and output + typedef itk::ImageRegionConstIterator InputImageIteratorType; + typedef itk::ImageRegionIterator OutputImageIteratorType; + typedef itk::ImageRegionIterator WeightsImageIteratorType; + + //define them over the outputRegionForThread + OutputImageIteratorType outputIt(outputPtr, outputRegionForThread); + InputImageIteratorType inputIt(inputPtr, outputRegionForThread); + WeightsImageIteratorType weightsIt(m_Weights, outputRegionForThread); + + + //================================================================================================== + //loop over the output and normalize the input, remove holes + PixelType neighValue; + double zero = itk::NumericTraits::Zero; + while (!outputIt.IsAtEnd()) + { + //the weight is not zero + if (weightsIt.Get() != zero) + { + //divide by the weight + outputIt.Set(static_cast(inputIt.Get()/weightsIt.Get())); + } + + //copy the value of the neighbour that was just processed + else + { + if(!outputIt.IsAtBegin()) + { + //go back + --outputIt; + + //Neighbour cannot have zero weight because it should be filled already + neighValue=outputIt.Get(); + ++outputIt; + outputIt.Set(neighValue); + //DD("hole filled"); + } + else{ + //DD("is at begin, setting edgepadding value"); + outputIt.Set(m_EdgePaddingValue); + } + } + ++weightsIt; + ++outputIt; + ++inputIt; + + }//end while + }//end member + + +}//end nameless namespace + + + +namespace clitk +{ + + //========================================================================================================================= + // The rest is the InvertVFFilter + //========================================================================================================================= + + //========================================================================================================================= + //constructor + template + InvertVFFilter::InvertVFFilter() + { + m_EdgePaddingValue=itk::NumericTraits::Zero; //no other reasonable value? + m_ThreadSafe=false; + m_Verbose=false; + } + + + //========================================================================================================================= + //Update + template void InvertVFFilter::GenerateData() + { + + //Get the properties of the input + typename InputImageType::ConstPointer inputPtr=this->GetInput(); + typename WeightsImageType::RegionType region; + typename WeightsImageType::RegionType::SizeType size=inputPtr->GetLargestPossibleRegion().GetSize(); + region.SetSize(size); + typename OutputImageType::IndexType start; + for (unsigned int i=0; i< ImageDimension; i++) start[i]=0; + region.SetIndex(start); + PixelType zero = itk::NumericTraits::Zero; + + + //Allocate the weights + typename WeightsImageType::Pointer weights=WeightsImageType::New(); + weights->SetRegions(region); + weights->Allocate(); + weights->SetSpacing(inputPtr->GetSpacing()); + + //=========================================================================== + //Inversion is divided in in two loops, for each we will call a threaded helper class + //1. add contribution of input to output and update weights + //2. normalize the output by the weight and remove holes + //=========================================================================== + + + //=========================================================================== + //1. add contribution of input to output and update weights + + //Define an internal image type + + typedef itk::Image, ImageDimension > InternalImageType; + + //Call threaded helper class 1 + typedef HelperClass1 HelperClass1Type; + typename HelperClass1Type::Pointer helper1=HelperClass1Type::New(); + + //Set input + if(m_NumberOfThreadsIsGiven)helper1->SetNumberOfThreads(m_NumberOfThreads); + helper1->SetInput(inputPtr); + helper1->SetWeights(weights); + + //Threadsafe? + if(m_ThreadSafe) + { + //Allocate the mutex image + typename MutexImageType::Pointer mutex=InvertVFFilter::MutexImageType::New(); + mutex->SetRegions(region); + mutex->Allocate(); + mutex->SetSpacing(inputPtr->GetSpacing()); + helper1->SetMutexImage(mutex); + if (m_Verbose) std::cout <<"Inverting using a thread-safe algorithm" <Update(); + + //Get the output + typename InternalImageType::Pointer temp= helper1->GetOutput(); + weights=helper1->GetWeights(); + + + //=========================================================================== + //2. Normalize the output by the weights and remove holes + //Call threaded helper class + typedef HelperClass2 HelperClass2Type; + typename HelperClass2Type::Pointer helper2=HelperClass2Type::New(); + + //Set temporary output as input + helper2->SetInput(temp); + helper2->SetWeights(weights); + helper2->SetEdgePaddingValue(m_EdgePaddingValue); + + //Execute helper class + if (m_Verbose) std::cout << "Normalizing the output VF..."<Update(); + + //Set the output + this->SetNthOutput(0, helper2->GetOutput()); + } + + + +} + +#endif diff --git a/itk/clitkSetBackgroundImageFilter.h b/itk/clitkSetBackgroundImageFilter.h new file mode 100644 index 0000000..09bc069 --- /dev/null +++ b/itk/clitkSetBackgroundImageFilter.h @@ -0,0 +1,215 @@ +#ifndef __clitkSetBackgroundImageFilter_h +#define __clitkSetBackgroundImageFilter_h + +#include "itkBinaryFunctorImageFilter.h" +#include "itkNumericTraits.h" + + +namespace clitk +{ + +namespace Functor { + +template< class TInput, class TMask, class TOutput=TInput > +class SetBackground +{ +public: + typedef typename itk::NumericTraits< TInput >::AccumulateType AccumulatorType; + + //SetBackground(): m_OutsideValue(itk::NumericTraits< TOutput >::Zero),m_Fg(false),m_MaskValue( static_cast(0) ) {}; + SetBackground() + { + m_OutsideValue=itk::NumericTraits< TOutput >::Zero; + m_Fg=false; + m_MaskValue= static_cast(0); + } + ~SetBackground() {}; + bool operator!=( const SetBackground & ) const + { + return false; + } + bool operator==( const SetBackground & other ) const + { + return !(*this != other); + } + + inline TOutput operator()( const TInput & A, const TMask & B) + { + // Background mode: set everything = background value + if(!m_Fg) + { + if (B == m_MaskValue ) + { + return static_cast( m_OutsideValue ); + } + else + { + return A; + } + } + + // Foreground mode: set everything != foreground value + else + { + if (B != m_MaskValue ) + { + return static_cast( m_OutsideValue ); + } + else + { + return A; + } + } + } + + /** Method to explicitly set the outside value of the mask */ + void SetOutsideValue( const TOutput &outsideValue ) + { + m_OutsideValue = static_cast(outsideValue); + } + + /** Method to get the outside value of the mask */ + const TOutput &GetOutsideValue() const + { + return m_OutsideValue; + } + + /** Method to explicitly set the relevant value of the mask */ + void SetMaskValue( const TMask &maskValue ) + { + m_MaskValue = static_cast(maskValue); + } + + /** Method to get the relevant value of the mask */ + const TMask &GetMaskValue() const + { + return m_MaskValue; + } + + /** Method to explicitly set the foreground mode of the mask */ + void SetForeground( const bool &fg ) + { + m_Fg = fg; + } + + /** Method to get the foregroundmode of the mask */ + const bool &GetForeground() const + { + return m_Fg; + } + +private: + TOutput m_OutsideValue; + TMask m_MaskValue; + bool m_Fg; +}; + +} //end namespace + +template +class ITK_EXPORT SetBackgroundImageFilter : + public + itk::BinaryFunctorImageFilter > + + +{ +public: + /** Standard class typedefs. */ + typedef SetBackgroundImageFilter Self; + typedef itk::BinaryFunctorImageFilter + > Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Runtime information support. */ + itkTypeMacro(SetBackgroundImageFilter, + BinaryFunctorImageFilter); + + /** Method to explicitly set the outside value of the mask. Defaults to 0 */ + void SetOutsideValue( const typename TOutputImage::PixelType & outsideValue ) + { + if( this->GetOutsideValue() != outsideValue ) + { + this->Modified(); + this->GetFunctor().SetOutsideValue( outsideValue ); + } + } + + const typename TOutputImage::PixelType & GetOutsideValue() const + { + return this->GetFunctor().GetOutsideValue(); + } + + /** Method to explicitly set the value of the mask. Defaults to 0 */ + void SetMaskValue( const typename TMaskImage::PixelType & maskValue ) + { + if( this->GetMaskValue() != maskValue ) + { + this->Modified(); + this->GetFunctor().SetMaskValue( maskValue ); + } + } + + const typename TMaskImage::PixelType & GetMaskValue() const + { + return this->GetFunctor().GetMaskValue(); + } + + /** Method to set the foreground mode. Defaults to 0 */ + void SetForeground( const bool & fg ) + { + if( this->GetForeground() != fg ) + { + this->Modified(); + this->GetFunctor().SetForeground( fg ); + } + } + + const bool & GetForeground() const + { + return this->GetFunctor().GetForeground(); + } + +#ifdef ITK_USE_CONCEPT_CHECKING + /** Begin concept checking */ + itkConceptMacro(MaskEqualityComparableCheck, + (itk::Concept::EqualityComparable)); + itkConceptMacro(InputConvertibleToOutputCheck, + (itk::Concept::Convertible)); + /** End concept checking */ +#endif + +protected: + SetBackgroundImageFilter() {} + virtual ~SetBackgroundImageFilter() {} + + void PrintSelf(std::ostream &os, itk::Indent indent) const + { + Superclass::PrintSelf(os, indent); + os << indent << "OutsideValue: " << this->GetOutsideValue() << std::endl; + os << indent << "MaskValue: " << this->GetMaskValue() << std::endl; + os << indent << "Foreground mode: " << this->GetForeground() << std::endl; + } + +private: + SetBackgroundImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + +}; + +} // end namespace clitk + + +#endif diff --git a/itk/clitkVectorBSplineDecompositionImageFilter.h b/itk/clitkVectorBSplineDecompositionImageFilter.h new file mode 100644 index 0000000..7e305d5 --- /dev/null +++ b/itk/clitkVectorBSplineDecompositionImageFilter.h @@ -0,0 +1,133 @@ +#ifndef __clitkVectorBSplineDecompositionImageFilter_h +#define __clitkVectorBSplineDecompositionImageFilter_h + +#include + +#include "itkImageLinearIteratorWithIndex.h" +#include "vnl/vnl_matrix.h" + +#include "itkImageToImageFilter.h" + +namespace clitk +{ + +template +class ITK_EXPORT VectorBSplineDecompositionImageFilter : + public itk::ImageToImageFilter +{ +public: + /** Standard class typedefs. */ + typedef VectorBSplineDecompositionImageFilter Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Run-time type information (and related methods). */ + itkTypeMacro(VectorBSplineDecompositionImageFilter, ImageToImageFilter); + + /** New macro for creation of through a Smart Pointer */ + itkNewMacro( Self ); + + /** Inherit input and output image types from Superclass. */ + typedef typename Superclass::InputImageType InputImageType; + typedef typename Superclass::InputImagePointer InputImagePointer; + typedef typename Superclass::InputImageConstPointer InputImageConstPointer; + typedef typename Superclass::OutputImagePointer OutputImagePointer; + + /** Dimension underlying input image. */ + itkStaticConstMacro(ImageDimension, unsigned int,TInputImage::ImageDimension); + itkStaticConstMacro(OutputImageDimension, unsigned int,TOutputImage::ImageDimension); + + //JV vector dimension + itkStaticConstMacro(VectorDimension, unsigned int,TInputImage::PixelType::Dimension); + + /** Iterator typedef support */ + typedef itk::ImageLinearIteratorWithIndex OutputLinearIterator; + + /** Get/Sets the Spline Order, supports 0th - 5th order splines. The default + * is a 3rd order spline. */ + void SetSplineOrder(unsigned int SplineOrder); + itkGetMacro(SplineOrder, int); + + + //JV modified from the original "double" version +#ifdef ITK_USE_CONCEPT_CHECKING + /** Begin concept checking */ + itkConceptMacro(DimensionCheck, + (itk::Concept::SameDimension)); + itkConceptMacro(InputConvertibleToDoubleCheck, + (itk::Concept::Convertible >)); + itkConceptMacro(OutputConvertibleToDoubleCheck, + (itk::Concept::Convertible >)); + itkConceptMacro(InputConvertibleToOutputCheck, + (itk::Concept::Convertible)); + itkConceptMacro(DoubleConvertibleToOutputCheck, + (itk::Concept::Convertible, typename TOutputImage::PixelType>)); + /** End concept checking */ +#endif + +protected: + VectorBSplineDecompositionImageFilter(); + virtual ~VectorBSplineDecompositionImageFilter() {}; + void PrintSelf(std::ostream& os, itk::Indent indent) const; + + void GenerateData( ); + + /** This filter requires all of the input image. */ + void GenerateInputRequestedRegion(); + + /** This filter must produce all of its output at once. */ + void EnlargeOutputRequestedRegion( itk::DataObject *output ); + + /** These are needed by the smoothing spline routine. */ + //JV + std::vector< itk::Vector > m_Scratch; // temp storage for processing of Coefficients + typename TInputImage::SizeType m_DataLength; // Image size + unsigned int m_SplineOrder; // User specified spline order (3rd or cubic is the default) + double m_SplinePoles[3];// Poles calculated for a given spline order + int m_NumberOfPoles; // number of poles + double m_Tolerance; // Tolerance used for determining initial causal coefficient + unsigned int m_IteratorDirection; // Direction for iterator incrementing + + +private: + VectorBSplineDecompositionImageFilter( const Self& ); //purposely not implemented + void operator=( const Self& ); //purposely not implemented + + /** Determines the poles given the Spline Order. */ + virtual void SetPoles(); + + /** Converts a vector of data to a vector of Spline coefficients. */ + virtual bool DataToCoefficients1D(); + + /** Converts an N-dimension image of data to an equivalent sized image + * of spline coefficients. */ + void DataToCoefficientsND(); + + /** Determines the first coefficient for the causal filtering of the data. */ + virtual void SetInitialCausalCoefficient(double z); + + /** Determines the first coefficient for the anti-causal filtering of the data. */ + virtual void SetInitialAntiCausalCoefficient(double z); + + /** Used to initialize the Coefficients image before calculation. */ + void CopyImageToImage(); + + /** Copies a vector of data from the Coefficients image to the m_Scratch vector. */ + void CopyCoefficientsToScratch( OutputLinearIterator & ); + + /** Copies a vector of data from m_Scratch to the Coefficients image. */ + void CopyScratchToCoefficients( OutputLinearIterator & ); + +}; + + +} // namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkVectorBSplineDecompositionImageFilter.txx" +#endif + +#endif + diff --git a/itk/clitkVectorBSplineDecompositionImageFilter.txx b/itk/clitkVectorBSplineDecompositionImageFilter.txx new file mode 100644 index 0000000..7699922 --- /dev/null +++ b/itk/clitkVectorBSplineDecompositionImageFilter.txx @@ -0,0 +1,418 @@ +#ifndef _clitkVectorBSplineDecompositionImageFilter_txx +#define _clitkVectorBSplineDecompositionImageFilter_txx + +#include "clitkVectorBSplineDecompositionImageFilter.h" +#include "itkImageRegionConstIteratorWithIndex.h" +#include "itkImageRegionIterator.h" +#include "itkProgressReporter.h" +#include "itkVector.h" + +namespace clitk +{ + +/** + * Constructor + */ +template +VectorBSplineDecompositionImageFilter +::VectorBSplineDecompositionImageFilter() +{ + m_SplineOrder = 0; + int SplineOrder = 3; + m_Tolerance = 1e-10; // Need some guidance on this one...what is reasonable? + m_IteratorDirection = 0; + this->SetSplineOrder(SplineOrder); +} + + +/** + * Standard "PrintSelf" method + */ +template +void +VectorBSplineDecompositionImageFilter +::PrintSelf( + std::ostream& os, + itk::Indent indent) const +{ + Superclass::PrintSelf( os, indent ); + os << indent << "Spline Order: " << m_SplineOrder << std::endl; + +} + + +template +bool +VectorBSplineDecompositionImageFilter +::DataToCoefficients1D() +{ + + // See Unser, 1993, Part II, Equation 2.5, + // or Unser, 1999, Box 2. for an explaination. + + double c0 = 1.0; + + if (m_DataLength[m_IteratorDirection] == 1) //Required by mirror boundaries + { + return false; + } + + // Compute overall gain + for (int k = 0; k < m_NumberOfPoles; k++) + { + // Note for cubic splines lambda = 6 + c0 = c0 * (1.0 - m_SplinePoles[k]) * (1.0 - 1.0 / m_SplinePoles[k]); + } + + // apply the gain + for (unsigned int n = 0; n < m_DataLength[m_IteratorDirection]; n++) + { + m_Scratch[n] *= c0; + } + + // loop over all poles + for (int k = 0; k < m_NumberOfPoles; k++) + { + // causal initialization + this->SetInitialCausalCoefficient(m_SplinePoles[k]); + // causal recursion + for (unsigned int n = 1; n < m_DataLength[m_IteratorDirection]; n++) + { + m_Scratch[n] += m_SplinePoles[k] * m_Scratch[n - 1]; + } + + // anticausal initialization + this->SetInitialAntiCausalCoefficient(m_SplinePoles[k]); + // anticausal recursion + for ( int n = m_DataLength[m_IteratorDirection] - 2; 0 <= n; n--) + { + m_Scratch[n] = m_SplinePoles[k] * (m_Scratch[n + 1] - m_Scratch[n]); + } + } + return true; + +} + + +template +void +VectorBSplineDecompositionImageFilter +::SetSplineOrder(unsigned int SplineOrder) +{ + if (SplineOrder == m_SplineOrder) + { + return; + } + m_SplineOrder = SplineOrder; + this->SetPoles(); + this->Modified(); + +} + + +template +void +VectorBSplineDecompositionImageFilter +::SetPoles() +{ + /* See Unser, 1997. Part II, Table I for Pole values */ + // See also, Handbook of Medical Imaging, Processing and Analysis, Ed. Isaac N. Bankman, + // 2000, pg. 416. + switch (m_SplineOrder) + { + case 3: + m_NumberOfPoles = 1; + m_SplinePoles[0] = vcl_sqrt(3.0) - 2.0; + break; + case 0: + m_NumberOfPoles = 0; + break; + case 1: + m_NumberOfPoles = 0; + break; + case 2: + m_NumberOfPoles = 1; + m_SplinePoles[0] = vcl_sqrt(8.0) - 3.0; + break; + case 4: + m_NumberOfPoles = 2; + m_SplinePoles[0] = vcl_sqrt(664.0 - vcl_sqrt(438976.0)) + vcl_sqrt(304.0) - 19.0; + m_SplinePoles[1] = vcl_sqrt(664.0 + vcl_sqrt(438976.0)) - vcl_sqrt(304.0) - 19.0; + break; + case 5: + m_NumberOfPoles = 2; + m_SplinePoles[0] = vcl_sqrt(135.0 / 2.0 - vcl_sqrt(17745.0 / 4.0)) + vcl_sqrt(105.0 / 4.0) + - 13.0 / 2.0; + m_SplinePoles[1] = vcl_sqrt(135.0 / 2.0 + vcl_sqrt(17745.0 / 4.0)) - vcl_sqrt(105.0 / 4.0) + - 13.0 / 2.0; + break; + default: + // SplineOrder not implemented yet. + itk::ExceptionObject err(__FILE__, __LINE__); + err.SetLocation( ITK_LOCATION); + err.SetDescription( "SplineOrder must be between 0 and 5. Requested spline order has not been implemented yet." ); + throw err; + break; + } +} + + +template +void +VectorBSplineDecompositionImageFilter +::SetInitialCausalCoefficient(double z) +{ + /* begining InitialCausalCoefficient */ + /* See Unser, 1999, Box 2 for explaination */ + //JV + itk::Vector sum; + double zn, z2n, iz; //sum + unsigned long horizon; + + /* this initialization corresponds to mirror boundaries */ + horizon = m_DataLength[m_IteratorDirection]; + zn = z; + if (m_Tolerance > 0.0) + { + horizon = (long)vcl_ceil(log(m_Tolerance) / vcl_log(fabs(z))); + } + if (horizon < m_DataLength[m_IteratorDirection]) + { + /* accelerated loop */ + sum = m_Scratch[0]; // verify this + for (unsigned int n = 1; n < horizon; n++) + { + sum += zn * m_Scratch[n]; + zn *= z; + } + m_Scratch[0] = sum; + } + else { + /* full loop */ + iz = 1.0 / z; + z2n = vcl_pow(z, (double)(m_DataLength[m_IteratorDirection] - 1L)); + sum = m_Scratch[0] + z2n * m_Scratch[m_DataLength[m_IteratorDirection] - 1L]; + z2n *= z2n * iz; + for (unsigned int n = 1; n <= (m_DataLength[m_IteratorDirection] - 2); n++) + { + sum += (zn + z2n) * m_Scratch[n]; + zn *= z; + z2n *= iz; + } + m_Scratch[0] = sum / (1.0 - zn * zn); + } +} + + +template +void +VectorBSplineDecompositionImageFilter +::SetInitialAntiCausalCoefficient(double z) +{ + // this initialization corresponds to mirror boundaries + /* See Unser, 1999, Box 2 for explaination */ + // Also see erratum at http://bigwww.epfl.ch/publications/unser9902.html + m_Scratch[m_DataLength[m_IteratorDirection] - 1] = + (z / (z * z - 1.0)) * + (z * m_Scratch[m_DataLength[m_IteratorDirection] - 2] + m_Scratch[m_DataLength[m_IteratorDirection] - 1]); +} + + +template +void +VectorBSplineDecompositionImageFilter +::DataToCoefficientsND() +{ + OutputImagePointer output = this->GetOutput(); + + itk::Size size = output->GetBufferedRegion().GetSize(); + + unsigned int count = output->GetBufferedRegion().GetNumberOfPixels() / size[0] * ImageDimension; + + itk::ProgressReporter progress(this, 0, count, 10); + + // Initialize coeffient array + this->CopyImageToImage(); // Coefficients are initialized to the input data + + for (unsigned int n=0; n < ImageDimension; n++) + { + m_IteratorDirection = n; + // Loop through each dimension + + // Initialize iterators + OutputLinearIterator CIterator( output, output->GetBufferedRegion() ); + CIterator.SetDirection( m_IteratorDirection ); + // For each data vector + while ( !CIterator.IsAtEnd() ) + { + // Copy coefficients to scratch + this->CopyCoefficientsToScratch( CIterator ); + + + // Perform 1D BSpline calculations + this->DataToCoefficients1D(); + + // Copy scratch back to coefficients. + // Brings us back to the end of the line we were working on. + CIterator.GoToBeginOfLine(); + this->CopyScratchToCoefficients( CIterator ); // m_Scratch = m_Image; + CIterator.NextLine(); + progress.CompletedPixel(); + } + } +} + + +/** + * Copy the input image into the output image + */ +template +void +VectorBSplineDecompositionImageFilter +::CopyImageToImage() +{ + + typedef itk::ImageRegionConstIteratorWithIndex< TInputImage > InputIterator; + typedef itk::ImageRegionIterator< TOutputImage > OutputIterator; + typedef typename TOutputImage::PixelType OutputPixelType; + + InputIterator inIt( this->GetInput(), this->GetInput()->GetBufferedRegion() ); + OutputIterator outIt( this->GetOutput(), this->GetOutput()->GetBufferedRegion() ); + + inIt = inIt.Begin(); + outIt = outIt.Begin(); + OutputPixelType v; + while ( !outIt.IsAtEnd() ) + { + for (unsigned int i=0; i< VectorDimension;i++) + { + v[i]= static_cast( inIt.Get()[i] ); + } + outIt.Set( v ); + ++inIt; + ++outIt; + } + +} + + +/** + * Copy the scratch to one line of the output image + */ +template +void +VectorBSplineDecompositionImageFilter +::CopyScratchToCoefficients(OutputLinearIterator & Iter) +{ + typedef typename TOutputImage::PixelType OutputPixelType; + unsigned long j = 0; + OutputPixelType v; + while ( !Iter.IsAtEndOfLine() ) + { + for(unsigned int i=0; i( m_Scratch[j][i]); + Iter.Set( v ); + ++Iter; + ++j; + } + +} + + +/** + * Copy one line of the output image to the scratch + */ +template +void +VectorBSplineDecompositionImageFilter +::CopyCoefficientsToScratch(OutputLinearIterator & Iter) +{ + unsigned long j = 0; + itk::Vector v; + while ( !Iter.IsAtEndOfLine() ) + { + for(unsigned int i=0; i( Iter.Get()[i] ); + m_Scratch[j] = v ; + ++Iter; + ++j; + } +} + + +/** + * GenerateInputRequestedRegion method. + */ +template +void +VectorBSplineDecompositionImageFilter +::GenerateInputRequestedRegion() +{ + // this filter requires the all of the input image to be in + // the buffer + InputImagePointer inputPtr = const_cast< TInputImage * > ( this->GetInput() ); + if( inputPtr ) + { + inputPtr->SetRequestedRegionToLargestPossibleRegion(); + } +} + + +/** + * EnlargeOutputRequestedRegion method. + */ +template +void +VectorBSplineDecompositionImageFilter +::EnlargeOutputRequestedRegion( itk::DataObject *output ) +{ + + // this filter requires the all of the output image to be in + // the buffer + TOutputImage *imgData; + imgData = dynamic_cast( output ); + if( imgData ) + { + imgData->SetRequestedRegionToLargestPossibleRegion(); + } + +} + +/** + * Generate data + */ +template +void +VectorBSplineDecompositionImageFilter +::GenerateData() +{ + DD("VectorBSplineDecompositionImageFilter GenerateData()"); + // Allocate scratch memory + InputImageConstPointer inputPtr = this->GetInput(); + m_DataLength = inputPtr->GetBufferedRegion().GetSize(); + + unsigned long maxLength = 0; + for ( unsigned int n = 0; n < ImageDimension; n++ ) + { + if ( m_DataLength[n] > maxLength ) + { + maxLength = m_DataLength[n]; + } + } + m_Scratch.resize( maxLength ); + + // Allocate memory for output image + OutputImagePointer outputPtr = this->GetOutput(); + outputPtr->SetBufferedRegion( outputPtr->GetRequestedRegion() ); + outputPtr->Allocate(); + + // Calculate actual output + this->DataToCoefficientsND(); + + // Clean up + m_Scratch.clear(); + +} + + +} // namespace clitk + +#endif diff --git a/itk/clitkVectorBSplineDecompositionImageFilterWithOBD.h b/itk/clitkVectorBSplineDecompositionImageFilterWithOBD.h new file mode 100644 index 0000000..bdaa44f --- /dev/null +++ b/itk/clitkVectorBSplineDecompositionImageFilterWithOBD.h @@ -0,0 +1,140 @@ +#ifndef __clitkVectorBSplineDecompositionImageFilterWithOBD_h +#define __clitkVectorBSplineDecompositionImageFilterWithOBD_h + +#include + +#include "itkImageLinearIteratorWithIndex.h" +#include "vnl/vnl_matrix.h" + +#include "itkImageToImageFilter.h" + +namespace clitk +{ + +template +class ITK_EXPORT VectorBSplineDecompositionImageFilterWithOBD : + public itk::ImageToImageFilter +{ +public: + /** Standard class typedefs. */ + typedef VectorBSplineDecompositionImageFilterWithOBD Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Run-time type information (and related methods). */ + itkTypeMacro(VectorBSplineDecompositionImageFilterWithOBD, ImageToImageFilter); + + /** New macro for creation of through a Smart Pointer */ + itkNewMacro( Self ); + + /** Inherit input and output image types from Superclass. */ + typedef typename Superclass::InputImageType InputImageType; + typedef typename Superclass::InputImagePointer InputImagePointer; + typedef typename Superclass::InputImageConstPointer InputImageConstPointer; + typedef typename Superclass::OutputImagePointer OutputImagePointer; + + /** Dimension underlying input image. */ + itkStaticConstMacro(ImageDimension, unsigned int,TInputImage::ImageDimension); + itkStaticConstMacro(OutputImageDimension, unsigned int,TOutputImage::ImageDimension); + + //JV add the size + typedef typename InputImageType::SizeType SizeType; + + //JV vector dimension + itkStaticConstMacro(VectorDimension, unsigned int,TInputImage::PixelType::Dimension); + + /** Iterator typedef support */ + typedef itk::ImageLinearIteratorWithIndex OutputLinearIterator; + + /** Get/Sets the Spline Order, supports 0th - 5th order splines. The default + * is a 3rd order spline. */ + void SetSplineOrder(unsigned int SplineOrder); + itkGetMacro(SplineOrder, int); + //JV Set the order by Dimension + void SetSplineOrders(SizeType); + + //JV modified from the original "double" version +#ifdef ITK_USE_CONCEPT_CHECKING + /** Begin concept checking */ + itkConceptMacro(DimensionCheck, + (itk::Concept::SameDimension)); + itkConceptMacro(InputConvertibleToDoubleCheck, + (itk::Concept::Convertible >)); + itkConceptMacro(OutputConvertibleToDoubleCheck, + (itk::Concept::Convertible >)); + itkConceptMacro(InputConvertibleToOutputCheck, + (itk::Concept::Convertible)); + itkConceptMacro(DoubleConvertibleToOutputCheck, + (itk::Concept::Convertible, typename TOutputImage::PixelType>)); + /** End concept checking */ +#endif + +protected: + VectorBSplineDecompositionImageFilterWithOBD(); + virtual ~VectorBSplineDecompositionImageFilterWithOBD() {}; + void PrintSelf(std::ostream& os, itk::Indent indent) const; + + void GenerateData( ); + + /** This filter requires all of the input image. */ + void GenerateInputRequestedRegion(); + + /** This filter must produce all of its output at once. */ + void EnlargeOutputRequestedRegion( itk::DataObject *output ); + + /** These are needed by the smoothing spline routine. */ + //JV multiple splineOrders + SizeType m_SplineOrders; //SplineOrder by dimension + + //JV + std::vector< itk::Vector > m_Scratch; // temp storage for processing of Coefficients + typename TInputImage::SizeType m_DataLength; // Image size + unsigned int m_SplineOrder; // User specified spline order (3rd or cubic is the default) + double m_SplinePoles[3];// Poles calculated for a given spline order + int m_NumberOfPoles; // number of poles + double m_Tolerance; // Tolerance used for determining initial causal coefficient + unsigned int m_IteratorDirection; // Direction for iterator incrementing + + +private: + VectorBSplineDecompositionImageFilterWithOBD( const Self& ); //purposely not implemented + void operator=( const Self& ); //purposely not implemented + + /** Determines the poles given the Spline Order. */ + virtual void SetPoles(); + + /** Converts a vector of data to a vector of Spline coefficients. */ + virtual bool DataToCoefficients1D(); + + /** Converts an N-dimension image of data to an equivalent sized image + * of spline coefficients. */ + void DataToCoefficientsND(); + + /** Determines the first coefficient for the causal filtering of the data. */ + virtual void SetInitialCausalCoefficient(double z); + + /** Determines the first coefficient for the anti-causal filtering of the data. */ + virtual void SetInitialAntiCausalCoefficient(double z); + + /** Used to initialize the Coefficients image before calculation. */ + void CopyImageToImage(); + + /** Copies a vector of data from the Coefficients image to the m_Scratch vector. */ + void CopyCoefficientsToScratch( OutputLinearIterator & ); + + /** Copies a vector of data from m_Scratch to the Coefficients image. */ + void CopyScratchToCoefficients( OutputLinearIterator & ); + +}; + + +} // namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkVectorBSplineDecompositionImageFilterWithOBD.txx" +#endif + +#endif + diff --git a/itk/clitkVectorBSplineDecompositionImageFilterWithOBD.txx b/itk/clitkVectorBSplineDecompositionImageFilterWithOBD.txx new file mode 100644 index 0000000..992eb61 --- /dev/null +++ b/itk/clitkVectorBSplineDecompositionImageFilterWithOBD.txx @@ -0,0 +1,429 @@ +#ifndef _clitkVectorBSplineDecompositionImageFilterWithOBD_txx +#define _clitkVectorBSplineDecompositionImageFilterWithOBD_txx + +#include "clitkVectorBSplineDecompositionImageFilterWithOBD.h" +#include "itkImageRegionConstIteratorWithIndex.h" +#include "itkImageRegionIterator.h" +#include "itkProgressReporter.h" +#include "itkVector.h" + +namespace clitk +{ + +/** + * Constructor + */ +template +VectorBSplineDecompositionImageFilterWithOBD +::VectorBSplineDecompositionImageFilterWithOBD() +{ + m_SplineOrder = 0; + int SplineOrder = 3; + m_Tolerance = 1e-10; // Need some guidance on this one...what is reasonable? + m_IteratorDirection = 0; + this->SetSplineOrder(SplineOrder); +} + + +/** + * Standard "PrintSelf" method + */ +template +void +VectorBSplineDecompositionImageFilterWithOBD +::PrintSelf( + std::ostream& os, + itk::Indent indent) const +{ + Superclass::PrintSelf( os, indent ); + os << indent << "Spline Order: " << m_SplineOrder << std::endl; + +} + + +template +bool +VectorBSplineDecompositionImageFilterWithOBD +::DataToCoefficients1D() +{ + + // See Unser, 1993, Part II, Equation 2.5, + // or Unser, 1999, Box 2. for an explaination. + + double c0 = 1.0; + + if (m_DataLength[m_IteratorDirection] == 1) //Required by mirror boundaries + { + return false; + } + + // Compute overall gain + for (int k = 0; k < m_NumberOfPoles; k++) + { + // Note for cubic splines lambda = 6 + c0 = c0 * (1.0 - m_SplinePoles[k]) * (1.0 - 1.0 / m_SplinePoles[k]); + } + + // apply the gain + for (unsigned int n = 0; n < m_DataLength[m_IteratorDirection]; n++) + { + m_Scratch[n] *= c0; + } + + // loop over all poles + for (int k = 0; k < m_NumberOfPoles; k++) + { + // causal initialization + this->SetInitialCausalCoefficient(m_SplinePoles[k]); + // causal recursion + for (unsigned int n = 1; n < m_DataLength[m_IteratorDirection]; n++) + { + m_Scratch[n] += m_SplinePoles[k] * m_Scratch[n - 1]; + } + + // anticausal initialization + this->SetInitialAntiCausalCoefficient(m_SplinePoles[k]); + // anticausal recursion + for ( int n = m_DataLength[m_IteratorDirection] - 2; 0 <= n; n--) + { + m_Scratch[n] = m_SplinePoles[k] * (m_Scratch[n + 1] - m_Scratch[n]); + } + } + return true; + +} + + +template +void +VectorBSplineDecompositionImageFilterWithOBD +::SetSplineOrder(unsigned int SplineOrder) +{ + if (SplineOrder == m_SplineOrder) + { + return; + } + m_SplineOrder = SplineOrder; + this->SetPoles(); + this->Modified(); + +} + +//JV +template +void +VectorBSplineDecompositionImageFilterWithOBD +::SetSplineOrders(SizeType SplineOrders) +{ + m_SplineOrders=SplineOrders; +} + +template +void +VectorBSplineDecompositionImageFilterWithOBD +::SetPoles() +{ + /* See Unser, 1997. Part II, Table I for Pole values */ + // See also, Handbook of Medical Imaging, Processing and Analysis, Ed. Isaac N. Bankman, + // 2000, pg. 416. + switch (m_SplineOrder) + { + case 3: + m_NumberOfPoles = 1; + m_SplinePoles[0] = vcl_sqrt(3.0) - 2.0; + break; + case 0: + m_NumberOfPoles = 0; + break; + case 1: + m_NumberOfPoles = 0; + break; + case 2: + m_NumberOfPoles = 1; + m_SplinePoles[0] = vcl_sqrt(8.0) - 3.0; + break; + case 4: + m_NumberOfPoles = 2; + m_SplinePoles[0] = vcl_sqrt(664.0 - vcl_sqrt(438976.0)) + vcl_sqrt(304.0) - 19.0; + m_SplinePoles[1] = vcl_sqrt(664.0 + vcl_sqrt(438976.0)) - vcl_sqrt(304.0) - 19.0; + break; + case 5: + m_NumberOfPoles = 2; + m_SplinePoles[0] = vcl_sqrt(135.0 / 2.0 - vcl_sqrt(17745.0 / 4.0)) + vcl_sqrt(105.0 / 4.0) + - 13.0 / 2.0; + m_SplinePoles[1] = vcl_sqrt(135.0 / 2.0 + vcl_sqrt(17745.0 / 4.0)) - vcl_sqrt(105.0 / 4.0) + - 13.0 / 2.0; + break; + default: + // SplineOrder not implemented yet. + itk::ExceptionObject err(__FILE__, __LINE__); + err.SetLocation( ITK_LOCATION); + err.SetDescription( "SplineOrder must be between 0 and 5. Requested spline order has not been implemented yet." ); + throw err; + break; + } +} + + +template +void +VectorBSplineDecompositionImageFilterWithOBD +::SetInitialCausalCoefficient(double z) +{ + /* begining InitialCausalCoefficient */ + /* See Unser, 1999, Box 2 for explaination */ + //JV + itk::Vector sum; + double zn, z2n, iz; //sum + unsigned long horizon; + + /* this initialization corresponds to mirror boundaries */ + horizon = m_DataLength[m_IteratorDirection]; + zn = z; + if (m_Tolerance > 0.0) + { + horizon = (long)vcl_ceil(log(m_Tolerance) / vcl_log(fabs(z))); + } + if (horizon < m_DataLength[m_IteratorDirection]) + { + /* accelerated loop */ + sum = m_Scratch[0]; // verify this + for (unsigned int n = 1; n < horizon; n++) + { + sum += zn * m_Scratch[n]; + zn *= z; + } + m_Scratch[0] = sum; + } + else { + /* full loop */ + iz = 1.0 / z; + z2n = vcl_pow(z, (double)(m_DataLength[m_IteratorDirection] - 1L)); + sum = m_Scratch[0] + z2n * m_Scratch[m_DataLength[m_IteratorDirection] - 1L]; + z2n *= z2n * iz; + for (unsigned int n = 1; n <= (m_DataLength[m_IteratorDirection] - 2); n++) + { + sum += (zn + z2n) * m_Scratch[n]; + zn *= z; + z2n *= iz; + } + m_Scratch[0] = sum / (1.0 - zn * zn); + } +} + + +template +void +VectorBSplineDecompositionImageFilterWithOBD +::SetInitialAntiCausalCoefficient(double z) +{ + // this initialization corresponds to mirror boundaries + /* See Unser, 1999, Box 2 for explaination */ + // Also see erratum at http://bigwww.epfl.ch/publications/unser9902.html + m_Scratch[m_DataLength[m_IteratorDirection] - 1] = + (z / (z * z - 1.0)) * + (z * m_Scratch[m_DataLength[m_IteratorDirection] - 2] + m_Scratch[m_DataLength[m_IteratorDirection] - 1]); +} + + +template +void +VectorBSplineDecompositionImageFilterWithOBD +::DataToCoefficientsND() +{ + OutputImagePointer output = this->GetOutput(); + + itk::Size size = output->GetBufferedRegion().GetSize(); + + unsigned int count = output->GetBufferedRegion().GetNumberOfPixels() / size[0] * ImageDimension; + + itk::ProgressReporter progress(this, 0, count, 10); + + // Initialize coeffient array + this->CopyImageToImage(); // Coefficients are initialized to the input data + + for (unsigned int n=0; n < ImageDimension; n++) + { + m_IteratorDirection = n; + // Loop through each dimension + + //JV Set the correct order by dimension! + SetSplineOrder(m_SplineOrders[n]); + + // Initialize iterators + OutputLinearIterator CIterator( output, output->GetBufferedRegion() ); + CIterator.SetDirection( m_IteratorDirection ); + // For each data vector + while ( !CIterator.IsAtEnd() ) + { + // Copy coefficients to scratch + this->CopyCoefficientsToScratch( CIterator ); + + + // Perform 1D BSpline calculations + this->DataToCoefficients1D(); + + // Copy scratch back to coefficients. + // Brings us back to the end of the line we were working on. + CIterator.GoToBeginOfLine(); + this->CopyScratchToCoefficients( CIterator ); // m_Scratch = m_Image; + CIterator.NextLine(); + progress.CompletedPixel(); + } + } +} + + +/** + * Copy the input image into the output image + */ +template +void +VectorBSplineDecompositionImageFilterWithOBD +::CopyImageToImage() +{ + + typedef itk::ImageRegionConstIteratorWithIndex< TInputImage > InputIterator; + typedef itk::ImageRegionIterator< TOutputImage > OutputIterator; + typedef typename TOutputImage::PixelType OutputPixelType; + + InputIterator inIt( this->GetInput(), this->GetInput()->GetBufferedRegion() ); + OutputIterator outIt( this->GetOutput(), this->GetOutput()->GetBufferedRegion() ); + + inIt = inIt.Begin(); + outIt = outIt.Begin(); + OutputPixelType v; + while ( !outIt.IsAtEnd() ) + { + for (unsigned int i=0; i< VectorDimension;i++) + { + v[i]= static_cast( inIt.Get()[i] ); + } + outIt.Set( v ); + ++inIt; + ++outIt; + } + +} + + +/** + * Copy the scratch to one line of the output image + */ +template +void +VectorBSplineDecompositionImageFilterWithOBD +::CopyScratchToCoefficients(OutputLinearIterator & Iter) +{ + typedef typename TOutputImage::PixelType OutputPixelType; + unsigned long j = 0; + OutputPixelType v; + while ( !Iter.IsAtEndOfLine() ) + { + for(unsigned int i=0; i( m_Scratch[j][i]); + Iter.Set( v ); + ++Iter; + ++j; + } + +} + + +/** + * Copy one line of the output image to the scratch + */ +template +void +VectorBSplineDecompositionImageFilterWithOBD +::CopyCoefficientsToScratch(OutputLinearIterator & Iter) +{ + unsigned long j = 0; + itk::Vector v; + while ( !Iter.IsAtEndOfLine() ) + { + for(unsigned int i=0; i( Iter.Get()[i] ); + m_Scratch[j] = v ; + ++Iter; + ++j; + } +} + + +/** + * GenerateInputRequestedRegion method. + */ +template +void +VectorBSplineDecompositionImageFilterWithOBD +::GenerateInputRequestedRegion() +{ + // this filter requires the all of the input image to be in + // the buffer + InputImagePointer inputPtr = const_cast< TInputImage * > ( this->GetInput() ); + if( inputPtr ) + { + inputPtr->SetRequestedRegionToLargestPossibleRegion(); + } +} + + +/** + * EnlargeOutputRequestedRegion method. + */ +template +void +VectorBSplineDecompositionImageFilterWithOBD +::EnlargeOutputRequestedRegion( itk::DataObject *output ) +{ + + // this filter requires the all of the output image to be in + // the buffer + TOutputImage *imgData; + imgData = dynamic_cast( output ); + if( imgData ) + { + imgData->SetRequestedRegionToLargestPossibleRegion(); + } + +} + +/** + * Generate data + */ +template +void +VectorBSplineDecompositionImageFilterWithOBD +::GenerateData() +{ + DD("VectorBSplineDecompositionImageFilterWithOBD GenerateData()"); + // Allocate scratch memory + InputImageConstPointer inputPtr = this->GetInput(); + m_DataLength = inputPtr->GetBufferedRegion().GetSize(); + + unsigned long maxLength = 0; + for ( unsigned int n = 0; n < ImageDimension; n++ ) + { + if ( m_DataLength[n] > maxLength ) + { + maxLength = m_DataLength[n]; + } + } + m_Scratch.resize( maxLength ); + + // Allocate memory for output image + OutputImagePointer outputPtr = this->GetOutput(); + outputPtr->SetBufferedRegion( outputPtr->GetRequestedRegion() ); + outputPtr->Allocate(); + + // Calculate actual output + this->DataToCoefficientsND(); + + // Clean up + m_Scratch.clear(); + +} + + +} // namespace clitk + +#endif diff --git a/itk/clitkVectorBSplineInterpolateImageFunction.h b/itk/clitkVectorBSplineInterpolateImageFunction.h new file mode 100644 index 0000000..2bbbb57 --- /dev/null +++ b/itk/clitkVectorBSplineInterpolateImageFunction.h @@ -0,0 +1,201 @@ +#ifndef __clitkVectorBSplineInterpolateImageFunction_h +#define __clitkVectorBSplineInterpolateImageFunction_h + +#include "clitkVectorBSplineDecompositionImageFilter.h" + +// First make sure that the configuration is available. +// This line can be removed once the optimized versions +// gets integrated into the main directories. +#include "itkConfigure.h" + +// #ifdef ITK_USE_OPTIMIZED_REGISTRATION_METHODS +// #include "itkOptBSplineInterpolateImageFunction.h" +// #else + +#include + +#include "itkImageLinearIteratorWithIndex.h" +#include "itkVectorInterpolateImageFunction.h" +#include "vnl/vnl_matrix.h" + +#include "itkBSplineDecompositionImageFilter.h" +#include "itkConceptChecking.h" +#include "itkCovariantVector.h" + + +namespace clitk +{ + +template < + class TImageType, + class TCoordRep = double, + class TCoefficientType = double > +class ITK_EXPORT VectorBSplineInterpolateImageFunction : + public itk::VectorInterpolateImageFunction +{ +public: + /** Standard class typedefs. */ + typedef VectorBSplineInterpolateImageFunction Self; + typedef itk::VectorInterpolateImageFunction Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Run-time type information (and related methods). */ + itkTypeMacro(VectorBSplineInterpolateImageFunction, InterpolateImageFunction); + + + /** New macro for creation of through a Smart Pointer */ + itkNewMacro( Self ); + + /** OutputType typedef support. */ + typedef typename Superclass::OutputType OutputType; + + /** InputImageType typedef support. */ + typedef typename Superclass::InputImageType InputImageType; + + /** Dimension underlying input image. */ + itkStaticConstMacro(ImageDimension, unsigned int,Superclass::ImageDimension); + + /** Index typedef support. */ + typedef typename Superclass::IndexType IndexType; + + /** ContinuousIndex typedef support. */ + typedef typename Superclass::ContinuousIndexType ContinuousIndexType; + + /** PointType typedef support */ + typedef typename Superclass::PointType PointType; + + //JV the vector dimension + itkStaticConstMacro(VectorDimension, unsigned int,Superclass::Dimension); + + + /** Iterator typedef support */ + typedef itk::ImageLinearIteratorWithIndex Iterator; + + /** Internal Coefficient typedef support */ + typedef TCoefficientType CoefficientDataType; + + //JV + typedef itk::Vector CoefficientImagePixelType; + typedef itk::Image CoefficientImageType; + + /** Define filter for calculating the BSpline coefficients */ + //JV make vectorial + typedef clitk::VectorBSplineDecompositionImageFilter + CoefficientFilter; + typedef typename CoefficientFilter::Pointer CoefficientFilterPointer; + + /** Evaluate the function at a ContinuousIndex position. + * + * Returns the B-Spline interpolated image intensity at a + * specified point position. No bounds checking is done. + * The point is assume to lie within the image buffer. + * + * ImageFunction::IsInsideBuffer() can be used to check bounds before + * calling the method. */ + virtual OutputType EvaluateAtContinuousIndex( + const ContinuousIndexType & index ) const; + + /** Derivative typedef support */ + typedef itk::CovariantVector CovariantVectorType; + + CovariantVectorType EvaluateDerivative( const PointType & point ) const + { + ContinuousIndexType index; + this->GetInputImage()->TransformPhysicalPointToContinuousIndex( point, index ); + return ( this->EvaluateDerivativeAtContinuousIndex( index ) ); + } + + CovariantVectorType EvaluateDerivativeAtContinuousIndex( + const ContinuousIndexType & x ) const; + + + /** Get/Sets the Spline Order, supports 0th - 5th order splines. The default + * is a 3rd order spline. */ + void SetSplineOrder(unsigned int SplineOrder); + itkGetMacro(SplineOrder, int); + + + /** Set the input image. This must be set by the user. */ + virtual void SetInputImage(const TImageType * inputData); + + + /** The UseImageDirection flag determines whether image derivatives are + * computed with respect to the image grid or with respect to the physical + * space. When this flag is ON the derivatives are computed with respect to + * the coodinate system of physical space. The difference is whether we take + * into account the image Direction or not. The flag ON will take into + * account the image direction and will result in an extra matrix + * multiplication compared to the amount of computation performed when the + * flag is OFF. This flag is OFF by default.*/ + itkSetMacro( UseImageDirection, bool ); + itkGetMacro( UseImageDirection, bool ); + itkBooleanMacro( UseImageDirection ); + + +protected: + VectorBSplineInterpolateImageFunction(); + virtual ~VectorBSplineInterpolateImageFunction() {}; + void operator=( const Self& ); //purposely not implemented + void PrintSelf(std::ostream& os, itk::Indent indent) const; + + // These are needed by the smoothing spline routine. + std::vector m_Scratch; // temp storage for processing of Coefficients + typename TImageType::SizeType m_DataLength; // Image size + unsigned int m_SplineOrder; // User specified spline order (3rd or cubic is the default) + + typename CoefficientImageType::ConstPointer m_Coefficients; // Spline coefficients + +private: + VectorBSplineInterpolateImageFunction( const Self& ); //purposely not implemented + /** Determines the weights for interpolation of the value x */ + void SetInterpolationWeights( const ContinuousIndexType & x, + const vnl_matrix & EvaluateIndex, + vnl_matrix & weights, + unsigned int splineOrder ) const; + + /** Determines the weights for the derivative portion of the value x */ + void SetDerivativeWeights( const ContinuousIndexType & x, + const vnl_matrix & EvaluateIndex, + vnl_matrix & weights, + unsigned int splineOrder ) const; + + /** Precomputation for converting the 1D index of the interpolation neighborhood + * to an N-dimensional index. */ + void GeneratePointsToIndex( ); + + /** Determines the indicies to use give the splines region of support */ + void DetermineRegionOfSupport( vnl_matrix & evaluateIndex, + const ContinuousIndexType & x, + unsigned int splineOrder ) const; + + /** Set the indicies in evaluateIndex at the boundaries based on mirror + * boundary conditions. */ + void ApplyMirrorBoundaryConditions(vnl_matrix & evaluateIndex, + unsigned int splineOrder) const; + + + Iterator m_CIterator; // Iterator for traversing spline coefficients. + unsigned long m_MaxNumberInterpolationPoints; // number of neighborhood points used for interpolation + std::vector m_PointsToIndex; // Preallocation of interpolation neighborhood indicies + + CoefficientFilterPointer m_CoefficientFilter; + + // flag to take or not the image direction into account when computing the + // derivatives. + bool m_UseImageDirection; + + +}; + +} // namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkVectorBSplineInterpolateImageFunction.txx" +#endif + +#endif + +//#endif diff --git a/itk/clitkVectorBSplineInterpolateImageFunction.txx b/itk/clitkVectorBSplineInterpolateImageFunction.txx new file mode 100644 index 0000000..d80178b --- /dev/null +++ b/itk/clitkVectorBSplineInterpolateImageFunction.txx @@ -0,0 +1,563 @@ +#ifndef _clitkVectorBSplineInterpolateImageFunction_txx +#define _clitkVectorBSplineInterpolateImageFunction_txx + +// First, make sure that we include the configuration file. +// This line may be removed once the ThreadSafeTransform gets +// integrated into ITK. +#include "itkConfigure.h" + +// Second, redirect to the optimized version if necessary +// #ifdef ITK_USE_OPTIMIZED_REGISTRATION_METHODS +// #include "itkOptVectorBSplineInterpolateImageFunction.txx" +// #else + +#include "clitkVectorBSplineInterpolateImageFunction.h" + + +#include "itkImageLinearIteratorWithIndex.h" +#include "itkImageRegionConstIteratorWithIndex.h" +#include "itkImageRegionIterator.h" + +#include "itkVector.h" + +#include "itkMatrix.h" + +namespace clitk +{ + +/** + * Constructor + */ +template +VectorBSplineInterpolateImageFunction +::VectorBSplineInterpolateImageFunction() +{ + m_SplineOrder = 0; + unsigned int SplineOrder = 3; + m_CoefficientFilter = CoefficientFilter::New(); + // ***TODO: Should we store coefficients in a variable or retrieve from filter? + m_Coefficients = CoefficientImageType::New(); + this->SetSplineOrder(SplineOrder); + this->m_UseImageDirection = false; +} + +/** + * Standard "PrintSelf" method + */ +template +void +VectorBSplineInterpolateImageFunction +::PrintSelf( + std::ostream& os, + itk::Indent indent) const +{ + Superclass::PrintSelf( os, indent ); + os << indent << "Spline Order: " << m_SplineOrder << std::endl; + os << indent << "UseImageDirection = " + << (this->m_UseImageDirection ? "On" : "Off") << std::endl; + +} + + +template +void +VectorBSplineInterpolateImageFunction +::SetInputImage(const TImageType * inputData) +{ + if ( inputData ) + { + + DD("calling decomposition filter"); + m_CoefficientFilter->SetInput(inputData); + + // the Coefficient Filter requires that the spline order and the input data be set. + // TODO: We need to ensure that this is only run once and only after both input and + // spline order have been set. Should we force an update after the + // splineOrder has been set also? + + m_CoefficientFilter->Update(); + m_Coefficients = m_CoefficientFilter->GetOutput(); + + + // Call the Superclass implementation after, in case the filter + // pulls in more of the input image + Superclass::SetInputImage(inputData); + + m_DataLength = inputData->GetBufferedRegion().GetSize(); + + } + else + { + m_Coefficients = NULL; + } +} + + +template +void +VectorBSplineInterpolateImageFunction +::SetSplineOrder(unsigned int SplineOrder) +{ + if (SplineOrder == m_SplineOrder) + { + return; + } + m_SplineOrder = SplineOrder; + m_CoefficientFilter->SetSplineOrder( SplineOrder ); + + //this->SetPoles();/ + m_MaxNumberInterpolationPoints = 1; + for (unsigned int n=0; n < ImageDimension; n++) + { + m_MaxNumberInterpolationPoints *= ( m_SplineOrder + 1); + } + this->GeneratePointsToIndex( ); +} + + +template +typename +VectorBSplineInterpolateImageFunction +::OutputType +VectorBSplineInterpolateImageFunction +::EvaluateAtContinuousIndex( const ContinuousIndexType & x ) const +{ + vnl_matrix EvaluateIndex(ImageDimension, ( m_SplineOrder + 1 )); + + // compute the interpolation indexes + this->DetermineRegionOfSupport(EvaluateIndex, x, m_SplineOrder); + + // Determine weights + vnl_matrix weights(ImageDimension, ( m_SplineOrder + 1 )); + SetInterpolationWeights( x, EvaluateIndex, weights, m_SplineOrder ); + + // Modify EvaluateIndex at the boundaries using mirror boundary conditions + this->ApplyMirrorBoundaryConditions(EvaluateIndex, m_SplineOrder); + + // perform interpolation + //JV + itk::Vector interpolated; + for (unsigned int i=0; i< VectorDimension; i++) interpolated[i]=itk::NumericTraits::Zero; + + IndexType coefficientIndex; + // Step through eachpoint in the N-dimensional interpolation cube. + for (unsigned int p = 0; p < m_MaxNumberInterpolationPoints; p++) + { + // translate each step into the N-dimensional index. + // IndexType pointIndex = PointToIndex( p ); + + double w = 1.0; + for (unsigned int n = 0; n < ImageDimension; n++ ) + { + + w *= weights[n][ m_PointsToIndex[p][n] ]; + coefficientIndex[n] = EvaluateIndex[n][m_PointsToIndex[p][n]]; // Build up ND index for coefficients. + } + // Convert our step p to the appropriate point in ND space in the + // m_Coefficients cube. + //JV shouldn't be necessary + for (unsigned int i=0; iGetPixel(coefficientIndex)[i]; + } + +/* double interpolated = 0.0; + IndexType coefficientIndex; + // Step through eachpoint in the N-dimensional interpolation cube. + for (unsigned int sp = 0; sp <= m_SplineOrder; sp++) + { + for (unsigned int sp1=0; sp1 <= m_SplineOrder; sp1++) + { + + double w = 1.0; + for (unsigned int n1 = 0; n1 < ImageDimension; n1++ ) + { + w *= weights[n1][ sp1 ]; + coefficientIndex[n1] = EvaluateIndex[n1][sp]; // Build up ND index for coefficients. + } + + interpolated += w * m_Coefficients->GetPixel(coefficientIndex); + } + } +*/ + return(interpolated); + +} + + +template +typename +VectorBSplineInterpolateImageFunction +:: CovariantVectorType +VectorBSplineInterpolateImageFunction +::EvaluateDerivativeAtContinuousIndex( const ContinuousIndexType & x ) const +{ + vnl_matrix EvaluateIndex(ImageDimension, ( m_SplineOrder + 1 )); + + // compute the interpolation indexes + // TODO: Do we need to revisit region of support for the derivatives? + this->DetermineRegionOfSupport(EvaluateIndex, x, m_SplineOrder); + + // Determine weights + vnl_matrix weights(ImageDimension, ( m_SplineOrder + 1 )); + SetInterpolationWeights( x, EvaluateIndex, weights, m_SplineOrder ); + + vnl_matrix weightsDerivative(ImageDimension, ( m_SplineOrder + 1)); + SetDerivativeWeights( x, EvaluateIndex, weightsDerivative, ( m_SplineOrder ) ); + + // Modify EvaluateIndex at the boundaries using mirror boundary conditions + this->ApplyMirrorBoundaryConditions(EvaluateIndex, m_SplineOrder); + + const InputImageType * inputImage = this->GetInputImage(); + const typename InputImageType::SpacingType & spacing = inputImage->GetSpacing(); + + // Calculate derivative + CovariantVectorType derivativeValue; + double tempValue; + IndexType coefficientIndex; + for (unsigned int n = 0; n < ImageDimension; n++) + { + derivativeValue[n] = 0.0; + for (unsigned int p = 0; p < m_MaxNumberInterpolationPoints; p++) + { + tempValue = 1.0 ; + for (unsigned int n1 = 0; n1 < ImageDimension; n1++) + { + //coefficientIndex[n1] = EvaluateIndex[n1][sp]; + coefficientIndex[n1] = EvaluateIndex[n1][m_PointsToIndex[p][n1]]; + + if (n1 == n) + { + //w *= weights[n][ m_PointsToIndex[p][n] ]; + tempValue *= weightsDerivative[n1][ m_PointsToIndex[p][n1] ]; + } + else + { + tempValue *= weights[n1][ m_PointsToIndex[p][n1] ]; + } + } + derivativeValue[n] += m_Coefficients->GetPixel(coefficientIndex) * tempValue ; + } + derivativeValue[n] /= spacing[n]; // take spacing into account + } + +#ifdef ITK_USE_ORIENTED_IMAGE_DIRECTION + if( this->m_UseImageDirection ) + { + CovariantVectorType orientedDerivative; + inputImage->TransformLocalVectorToPhysicalVector( derivativeValue, orientedDerivative ); + return orientedDerivative; + } +#endif + + return(derivativeValue); +} + + +template +void +VectorBSplineInterpolateImageFunction +::SetInterpolationWeights( const ContinuousIndexType & x, const vnl_matrix & EvaluateIndex, + vnl_matrix & weights, unsigned int splineOrder ) const +{ + // For speed improvements we could make each case a separate function and use + // function pointers to reference the correct weight order. + // Left as is for now for readability. + double w, w2, w4, t, t0, t1; + + switch (splineOrder) + { + case 3: + for (unsigned int n = 0; n < ImageDimension; n++) + { + w = x[n] - (double) EvaluateIndex[n][1]; + weights[n][3] = (1.0 / 6.0) * w * w * w; + weights[n][0] = (1.0 / 6.0) + 0.5 * w * (w - 1.0) - weights[n][3]; + weights[n][2] = w + weights[n][0] - 2.0 * weights[n][3]; + weights[n][1] = 1.0 - weights[n][0] - weights[n][2] - weights[n][3]; + } + break; + case 0: + for (unsigned int n = 0; n < ImageDimension; n++) + { + weights[n][0] = 1; // implements nearest neighbor + } + break; + case 1: + for (unsigned int n = 0; n < ImageDimension; n++) + { + w = x[n] - (double) EvaluateIndex[n][0]; + weights[n][1] = w; + weights[n][0] = 1.0 - w; + } + break; + case 2: + for (unsigned int n = 0; n < ImageDimension; n++) + { + /* x */ + w = x[n] - (double)EvaluateIndex[n][1]; + weights[n][1] = 0.75 - w * w; + weights[n][2] = 0.5 * (w - weights[n][1] + 1.0); + weights[n][0] = 1.0 - weights[n][1] - weights[n][2]; + } + break; + case 4: + for (unsigned int n = 0; n < ImageDimension; n++) + { + /* x */ + w = x[n] - (double)EvaluateIndex[n][2]; + w2 = w * w; + t = (1.0 / 6.0) * w2; + weights[n][0] = 0.5 - w; + weights[n][0] *= weights[n][0]; + weights[n][0] *= (1.0 / 24.0) * weights[n][0]; + t0 = w * (t - 11.0 / 24.0); + t1 = 19.0 / 96.0 + w2 * (0.25 - t); + weights[n][1] = t1 + t0; + weights[n][3] = t1 - t0; + weights[n][4] = weights[n][0] + t0 + 0.5 * w; + weights[n][2] = 1.0 - weights[n][0] - weights[n][1] - weights[n][3] - weights[n][4]; + } + break; + case 5: + for (unsigned int n = 0; n < ImageDimension; n++) + { + /* x */ + w = x[n] - (double)EvaluateIndex[n][2]; + w2 = w * w; + weights[n][5] = (1.0 / 120.0) * w * w2 * w2; + w2 -= w; + w4 = w2 * w2; + w -= 0.5; + t = w2 * (w2 - 3.0); + weights[n][0] = (1.0 / 24.0) * (1.0 / 5.0 + w2 + w4) - weights[n][5]; + t0 = (1.0 / 24.0) * (w2 * (w2 - 5.0) + 46.0 / 5.0); + t1 = (-1.0 / 12.0) * w * (t + 4.0); + weights[n][2] = t0 + t1; + weights[n][3] = t0 - t1; + t0 = (1.0 / 16.0) * (9.0 / 5.0 - t); + t1 = (1.0 / 24.0) * w * (w4 - w2 - 5.0); + weights[n][1] = t0 + t1; + weights[n][4] = t0 - t1; + } + break; + default: + // SplineOrder not implemented yet. + itk::ExceptionObject err(__FILE__, __LINE__); + err.SetLocation( ITK_LOCATION ); + err.SetDescription( "SplineOrder must be between 0 and 5. Requested spline order has not been implemented yet." ); + throw err; + break; + } + +} + +template +void +VectorBSplineInterpolateImageFunction +::SetDerivativeWeights( const ContinuousIndexType & x, const vnl_matrix & EvaluateIndex, + vnl_matrix & weights, unsigned int splineOrder ) const +{ + // For speed improvements we could make each case a separate function and use + // function pointers to reference the correct weight order. + // Another possiblity would be to loop inside the case statement (reducing the number + // of switch statement executions to one per routine call. + // Left as is for now for readability. + double w, w1, w2, w3, w4, w5, t, t0, t1, t2; + int derivativeSplineOrder = (int) splineOrder -1; + + switch (derivativeSplineOrder) + { + + // Calculates B(splineOrder) ( (x + 1/2) - xi) - B(splineOrder -1) ( (x - 1/2) - xi) + case -1: + // Why would we want to do this? + for (unsigned int n = 0; n < ImageDimension; n++) + { + weights[n][0] = 0.0; + } + break; + case 0: + for (unsigned int n = 0; n < ImageDimension; n++) + { + weights[n][0] = -1.0; + weights[n][1] = 1.0; + } + break; + case 1: + for (unsigned int n = 0; n < ImageDimension; n++) + { + w = x[n] + 0.5 - (double)EvaluateIndex[n][1]; + // w2 = w; + w1 = 1.0 - w; + + weights[n][0] = 0.0 - w1; + weights[n][1] = w1 - w; + weights[n][2] = w; + } + break; + case 2: + + for (unsigned int n = 0; n < ImageDimension; n++) + { + w = x[n] + .5 - (double)EvaluateIndex[n][2]; + w2 = 0.75 - w * w; + w3 = 0.5 * (w - w2 + 1.0); + w1 = 1.0 - w2 - w3; + + weights[n][0] = 0.0 - w1; + weights[n][1] = w1 - w2; + weights[n][2] = w2 - w3; + weights[n][3] = w3; + } + break; + case 3: + + for (unsigned int n = 0; n < ImageDimension; n++) + { + w = x[n] + 0.5 - (double)EvaluateIndex[n][2]; + w4 = (1.0 / 6.0) * w * w * w; + w1 = (1.0 / 6.0) + 0.5 * w * (w - 1.0) - w4; + w3 = w + w1 - 2.0 * w4; + w2 = 1.0 - w1 - w3 - w4; + + weights[n][0] = 0.0 - w1; + weights[n][1] = w1 - w2; + weights[n][2] = w2 - w3; + weights[n][3] = w3 - w4; + weights[n][4] = w4; + } + break; + case 4: + for (unsigned int n = 0; n < ImageDimension; n++) + { + w = x[n] + .5 - (double)EvaluateIndex[n][3]; + t2 = w * w; + t = (1.0 / 6.0) * t2; + w1 = 0.5 - w; + w1 *= w1; + w1 *= (1.0 / 24.0) * w1; + t0 = w * (t - 11.0 / 24.0); + t1 = 19.0 / 96.0 + t2 * (0.25 - t); + w2 = t1 + t0; + w4 = t1 - t0; + w5 = w1 + t0 + 0.5 * w; + w3 = 1.0 - w1 - w2 - w4 - w5; + + weights[n][0] = 0.0 - w1; + weights[n][1] = w1 - w2; + weights[n][2] = w2 - w3; + weights[n][3] = w3 - w4; + weights[n][4] = w4 - w5; + weights[n][5] = w5; + } + break; + + default: + // SplineOrder not implemented yet. + itk::ExceptionObject err(__FILE__, __LINE__); + err.SetLocation( ITK_LOCATION ); + err.SetDescription( "SplineOrder (for derivatives) must be between 1 and 5. Requested spline order has not been implemented yet." ); + throw err; + break; + } + +} + + +// Generates m_PointsToIndex; +template +void +VectorBSplineInterpolateImageFunction +::GeneratePointsToIndex( ) +{ + // m_PointsToIndex is used to convert a sequential location to an N-dimension + // index vector. This is precomputed to save time during the interpolation routine. + m_PointsToIndex.resize(m_MaxNumberInterpolationPoints); + for (unsigned int p = 0; p < m_MaxNumberInterpolationPoints; p++) + { + int pp = p; + unsigned long indexFactor[ImageDimension]; + indexFactor[0] = 1; + for (int j=1; j< static_cast(ImageDimension); j++) + { + indexFactor[j] = indexFactor[j-1] * ( m_SplineOrder + 1 ); + } + for (int j = (static_cast(ImageDimension) - 1); j >= 0; j--) + { + m_PointsToIndex[p][j] = pp / indexFactor[j]; + pp = pp % indexFactor[j]; + } + } +} + +template +void +VectorBSplineInterpolateImageFunction +::DetermineRegionOfSupport( vnl_matrix & evaluateIndex, + const ContinuousIndexType & x, + unsigned int splineOrder ) const +{ + long indx; + +// compute the interpolation indexes + for (unsigned int n = 0; n< ImageDimension; n++) + { + if (splineOrder & 1) // Use this index calculation for odd splineOrder + { + indx = (long)vcl_floor((float)x[n]) - splineOrder / 2; + for (unsigned int k = 0; k <= splineOrder; k++) + { + evaluateIndex[n][k] = indx++; + } + } + else // Use this index calculation for even splineOrder + { + indx = (long)vcl_floor((float)(x[n] + 0.5)) - splineOrder / 2; + for (unsigned int k = 0; k <= splineOrder; k++) + { + evaluateIndex[n][k] = indx++; + } + } + } +} + +template +void +VectorBSplineInterpolateImageFunction +::ApplyMirrorBoundaryConditions(vnl_matrix & evaluateIndex, + unsigned int splineOrder) const +{ + for (unsigned int n = 0; n < ImageDimension; n++) + { + long dataLength2 = 2 * m_DataLength[n] - 2; + + // apply the mirror boundary conditions + // TODO: We could implement other boundary options beside mirror + if (m_DataLength[n] == 1) + { + for (unsigned int k = 0; k <= splineOrder; k++) + { + evaluateIndex[n][k] = 0; + } + } + else + { + for (unsigned int k = 0; k <= splineOrder; k++) + { + // btw - Think about this couldn't this be replaced with a more elagent modulus method? + evaluateIndex[n][k] = (evaluateIndex[n][k] < 0L) ? (-evaluateIndex[n][k] - dataLength2 * ((-evaluateIndex[n][k]) / dataLength2)) + : (evaluateIndex[n][k] - dataLength2 * (evaluateIndex[n][k] / dataLength2)); + if ((long) m_DataLength[n] <= evaluateIndex[n][k]) + { + evaluateIndex[n][k] = dataLength2 - evaluateIndex[n][k]; + } + } + } + } +} + +} // namespace itk + +#endif + +//#endif diff --git a/itk/clitkVectorBSplineInterpolateImageFunctionWithLUT.h b/itk/clitkVectorBSplineInterpolateImageFunctionWithLUT.h new file mode 100644 index 0000000..75582a7 --- /dev/null +++ b/itk/clitkVectorBSplineInterpolateImageFunctionWithLUT.h @@ -0,0 +1,139 @@ +#ifndef __clitkVectorBSplineInterpolateImageFunctionWithLUT_h +#define __clitkVectorBSplineInterpolateImageFunctionWithLUT_h + +/* ========================================================================= + + @file clitVectorkBSplineInterpolateImageFunctionWithLUT.h + @author jefvdmb@gmail.com + + Copyright (c) + * CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). + All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + * Léon Bérard cancer center, 28 rue Laënnec, 69373 Lyon cedex 08, France + * http://www.creatis.insa-lyon.fr/rio + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +========================================================================= */ + +#include "itkBSplineWeightsCalculator.h" +//#include "clitkTimer.h" +#include "clitkVectorBSplineInterpolateImageFunction.h" + +namespace clitk { + + template < + class TImageType, + class TCoordRep = double, + class TCoefficientType = double > + class ITK_EXPORT VectorBSplineInterpolateImageFunctionWithLUT : + public VectorBSplineInterpolateImageFunction { + + public: + /** Class typedefs */ + typedef VectorBSplineInterpolateImageFunctionWithLUT Self; + typedef VectorBSplineInterpolateImageFunction Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + typedef typename Superclass::OutputType OutputType; + typedef typename Superclass::ContinuousIndexType ContinuousIndexType; + typedef typename TImageType::IndexType IndexType; + typedef typename TImageType::IndexValueType IndexValueType; + typedef typename TImageType::SizeType SizeType; + typedef typename TImageType::SpacingType SpacingType; + + typedef TCoefficientType CoefficientDataType; + typedef typename Superclass::CoefficientImagePixelType CoefficientImagePixelType; + typedef typename Superclass::CoefficientImageType CoefficientImageType; + + /** New macro for creation of through a Smart Pointer */ + itkNewMacro(Self); + + /** Setting LUT sampling (one parameters by dimension or a single + one for all dim); Default is 10 (for each dim) **/ + void SetLUTSamplingFactor(const int& s); + void SetLUTSamplingFactors(const SizeType& s); + + /** Get/Sets the Spline Order, supports 0th - 5th order + * splines. The default is a 3rd order spline. */ + void SetSplineOrder(const unsigned int & SplineOrder); + + //JV this is added to support different degrees over each dimension + void SetSplineOrders(const SizeType & SplineOrders); + + /** Set the input image. This must be set by the user. */ + virtual void SetInputImage(const TImageType * inputData); + //void SetOutputSpacing(const SpacingType & s); + //void SetInputImageIsCoefficient(bool inputIsCoef) { mInputIsCoef = inputIsCoef; } + + /** Evaluate the function at a ContinuousIndex position. + Overwritten for taking LUT into account */ + virtual OutputType EvaluateAtContinuousIndex(const ContinuousIndexType & index ) const; + void EvaluateWeightsAtContinuousIndex(const ContinuousIndexType & x, const TCoefficientType ** pweights, IndexType & evaluateIndex) const; + + /** Static convenient functions to compute BSpline weights for + various order, dimension, sampling ... **/ + static void ComputeBlendingWeights(int dim, int order, int sampling, TCoefficientType * weights); + + /** Timer giving computation time for coefficients computation **/ + // const clitk::Timer & GetCoefTimer() const { return mCoefficientTimer; } + + /** Get estimated error **/ + + double GetIntrinsicError() const { return *mIntrinsecError; } + long GetNumberOfError() const { return *mNumberOfError; } + double GetIntrinsicErrorMax() const { return *mIntrinsecErrorMax; } + + protected: + VectorBSplineInterpolateImageFunctionWithLUT(); + ~VectorBSplineInterpolateImageFunctionWithLUT(){;} + + SizeType mSupport; // nb of coef values used for interpolation (order+1) in 1 dimension + SizeType mHalfSupport; // half size of the previous + unsigned int mSupportSize; // Total support size for all dimension + std::vector mSupportOffset; // Memory pointer offset for going from one coef position to the other (inside the whole support) + std::vector mSupportIndex; // nD Index of all support values + IndexType mInputMemoryOffset; // Memory dimension offsets for input image + + /** Sampling factors for LUT weights **/ + SizeType mSamplingFactors; + bool mWeightsAreUpToDate; + //SpacingType mOutputSpacing; + + double * mIntrinsecError; + double * mIntrinsecErrorMax; + long * mNumberOfError; + + //JV add iscoeff, and splineorders + // bool mInputIsCoef; + SizeType mSplineOrders; + + // Filter to compute weights + itk::BSplineWeightsCalculator mWeightsCalculator; + + // Convenient functions + void UpdatePrecomputedWeights(); + void UpdateWeightsProperties(); + IndexType GetSampleIndexOfPixelPosition(const ContinuousIndexType & x, IndexType & EvaluateIndex) const; + + // Timing options + // clitk::Timer mCoefficientTimer; + // clitk::Timer mLUTTimer; + bool mTimerEnabled; + + //JV threadsafety: everything on the stack + //std::vector mCorrectedSupportOffset; + //std::vector mCorrectedSupportIndex; + TCoefficientType * coef; + + }; // end class clitkVectorBSplineInterpolateImageFunctionWithLUT +} // end namespace + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkVectorBSplineInterpolateImageFunctionWithLUT.txx" +#endif + +#endif /* end #define CLITKBSPLINEINTERPOLATEIMAGEFUNCTIONWITHLUT_H */ diff --git a/itk/clitkVectorBSplineInterpolateImageFunctionWithLUT.txx b/itk/clitkVectorBSplineInterpolateImageFunctionWithLUT.txx new file mode 100644 index 0000000..8cd0ab2 --- /dev/null +++ b/itk/clitkVectorBSplineInterpolateImageFunctionWithLUT.txx @@ -0,0 +1,438 @@ +#ifndef _CLITKVECTORBSPLINEINTERPOLATEIMAGEFUNCTIONWITHLUT_TXX +#define _CLITKVECTORBSPLINEINTERPOLATEIMAGEFUNCTIONWITHLUT_TXX + +/* ========================================================================= + +@file itkBSplineInterpolateImageFunctionWithLUT.txx +@author jefvdmb@gmail.com + +Copyright (c) +* CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). +All rights reserved. See Doc/License.txt or +http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. +* Léon Bérard cancer center, 28 rue Laënnec, 69373 Lyon cedex 08, France +* http://www.creatis.insa-lyon.fr/rio + +This software is distributed WITHOUT ANY WARRANTY; without even the +implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +========================================================================= */ +namespace clitk +{ + //==================================================================== + template + VectorBSplineInterpolateImageFunctionWithLUT:: + VectorBSplineInterpolateImageFunctionWithLUT():Superclass() { + // Set default values + //for(int i=0; i + void VectorBSplineInterpolateImageFunctionWithLUT:: + SetLUTSamplingFactor(const int& s) { + for(int i=0; i + void VectorBSplineInterpolateImageFunctionWithLUT:: + SetLUTSamplingFactors(const SizeType& s) { + for(int i=0; i + // void VectorBSplineInterpolateImageFunctionWithLUT:: + // SetOutputSpacing(const SpacingType & s) { + // for(int i=0; i + void VectorBSplineInterpolateImageFunctionWithLUT:: + SetSplineOrder(const unsigned int& SplineOrder) { + Superclass::SetSplineOrder(SplineOrder); + // Compute support and half size + static const int d = TImageType::ImageDimension; + for(int l=0; l + void VectorBSplineInterpolateImageFunctionWithLUT:: + SetSplineOrders(const SizeType& SplineOrders) { + mSplineOrders=SplineOrders; + + // Compute support and half size + static const int d = TImageType::ImageDimension; + for(int l=0; l + void VectorBSplineInterpolateImageFunctionWithLUT:: + SetInputImage(const TImageType * inputData) { + + //============================== + // if (!mInputIsCoef) + // { + Superclass::SetInputImage(inputData); + // } + + //============================== + // //JV Don't call superclass (decomposition filter is executeed each time!) + // else + // { + // this->m_Coefficients = inputData; + // if ( this->m_Coefficients.IsNotNull()) + // { + // this->m_DataLength = this->m_Coefficients->GetBufferedRegion().GetSize(); + // } + + // //Call super-superclass in case more input arrives + // itk::ImageFunction::RealType, TCoefficientType>::SetInputImage(inputData); + // } + + if (!inputData) return; + UpdateWeightsProperties(); + + } + + //==================================================================== + template + void VectorBSplineInterpolateImageFunctionWithLUT:: + UpdateWeightsProperties() { + + // Compute Memory offset inside coefficients images (for looping over coefficients) + static const unsigned int d = TImageType::ImageDimension; + mInputMemoryOffset[0] = 1; + for(unsigned int l=1; lm_Coefficients->GetLargestPossibleRegion().GetSize(l-1); + } + + //JV Put here? + if (!mWeightsAreUpToDate) + { + // Compute mSupportOffset according to input size + mSupportOffset.resize(mSupportSize); + mSupportIndex.resize(mSupportSize); + for(unsigned int l=0; l(mSupportIndex[k], mInputMemoryOffset); + // next coefficient index + if (k != mSupportSize-1) { + for(unsigned int l=0; l(mSupportIndex[k+1][l]) == mSupport[l]) { + mSupportIndex[k+1][l] = 0; + l++; + } + else stop = true; + } + } + } + + // // Check + // for(unsigned int l=0; l + void VectorBSplineInterpolateImageFunctionWithLUT:: + UpdatePrecomputedWeights() { + // mLUTTimer.Reset(); + // mLUTTimer.Start(); + mWeightsCalculator.SetSplineOrders(mSplineOrders); + mWeightsCalculator.SetSamplingFactors(mSamplingFactors); + mWeightsCalculator.ComputeTensorProducts(); + mWeightsAreUpToDate = true; + //DS + // coef = new TCoefficientType[mSupportSize]; + // mCorrectedSupportIndex.resize(mSupportSize); + // mCorrectedSupportOffset.resize(mSupportSize); + // mLUTTimer.Stop(); + // mLUTTimer.Print("LUT \t"); + } + //==================================================================== + + //==================================================================== + template + typename VectorBSplineInterpolateImageFunctionWithLUT::IndexType + VectorBSplineInterpolateImageFunctionWithLUT:: + GetSampleIndexOfPixelPosition(const ContinuousIndexType & x, IndexType & EvaluateIndex) const { + + /* + WARNING : sometimes, a floating number x could not really be + represented in memory. In this case, the difference between x and + floor(x) can be almost 1 (instead of 0). So we take into account + such special case, otherwise it could lead to annoying results. + */ + // static const TCoefficientType tiny = 1.0e-7; + IndexType index; + + for(int l=0; l *mIntrinsecErrorMax) *mIntrinsecErrorMax = fabs(index[l]-t2); + */ + + // When to close to 1, take the next coefficient for odd order, but + // only change index for odd + if (index[l] == (int)mSamplingFactors[l]) { + index[l] = 0; + if (mSplineOrders[l] & 1) EvaluateIndex[l] = EvaluateIndex[l]+1; + } + } + + // The end + return index; + } + + + //==================================================================== + + //==================================================================== + template + typename VectorBSplineInterpolateImageFunctionWithLUT::OutputType + VectorBSplineInterpolateImageFunctionWithLUT:: + EvaluateAtContinuousIndex(const ContinuousIndexType & x) const { + + // For shorter coding + static const unsigned int d = TImageType::ImageDimension; + + // Compute the index of the first interpolation coefficient in the coefficient image + IndexType evaluateIndex; + long indx; + for (unsigned int l=0; lm_SplineOrder / 2; + evaluateIndex[l] = indx; + } + else { // Use this index calculation for even splineOrder + if (mSplineOrders[l] == 0) evaluateIndex[l] = (long)rint(x[l]); + else { + indx = (long)vcl_floor((x[l]+ 0.5)) - mSplineOrders[l] / 2; //this->m_SplineOrder / 2; + evaluateIndex[l] = indx; + } + } + } + + // Compute index of precomputed weights and get pointer to first weights + const IndexType weightIndex = GetSampleIndexOfPixelPosition(x, evaluateIndex); + const TCoefficientType * pweights = mWeightsCalculator.GetFirstTensorProduct(weightIndex); + + // Check boundaries + bool boundaryCase = false; + for (unsigned int l=0; l= this->m_Coefficients->GetLargestPossibleRegion().GetSize(l)) { + boundaryCase = true; + } + } + + // Pointer to support offset + const int * psupport; + + // Special case for boundary (to be changed ....) + std::vector correctedSupportOffset; + if (boundaryCase) { + // return -1000; + //std::vector coef(mSupportSize); + // DD(EvaluateIndex); + //std::vector CorrectedSupportOffset;//(mSupportSize); + std::vector correctedSupportIndex;//(mSupportSize); + correctedSupportIndex.resize(mSupportSize); + correctedSupportOffset.resize(mSupportSize); + for(unsigned int i=0; im_Coefficients->GetLargestPossibleRegion().GetSize(l); + // DD(a); + // DD(b); + long d2 = 2 * b - 2; + if (a < 0) { + correctedSupportIndex[i][l] = -a - d2*(-a/d2) - evaluateIndex[l];//mSupportIndex[i][l]-a; + } + else { + if (a>=b) { + correctedSupportIndex[i][l] = d2 - a - evaluateIndex[l]; + } + else { + correctedSupportIndex[i][l] = mSupportIndex[i][l]; //a - d2*(a/d2) - EvaluateIndex[l]; + } + /* + if (a>=b) { + correctedSupportIndex[i][l] = d2 - a - EvaluateIndex[l];//mSupportIndex[i][l] - (a-(b-1)); + } + else { + correctedSupportIndex[i][l] = mSupportIndex[i][l]; + } + */ + } + } + // DD(correctedSupportIndex[i]); + correctedSupportOffset[i] = itk::Index2Offset(correctedSupportIndex[i], mInputMemoryOffset); + } + // for (unsigned int l=0; lm_Coefficients->GetPixel(evaluateIndex)); + + // Main loop over BSpline support + CoefficientImagePixelType interpolated = 0.0; + for (unsigned int p=0; p + void + VectorBSplineInterpolateImageFunctionWithLUT:: + EvaluateWeightsAtContinuousIndex(const ContinuousIndexType& x, const TCoefficientType ** pweights, IndexType & evaluateIndex)const { + + // JV Compute BSpline weights if not up to date! Problem const: pass image as last + // if (!mWeightsAreUpToDate) UpdatePrecomputedWeights(); + + // For shorter coding + static const unsigned int d = TImageType::ImageDimension; + + // Compute the index of the first interpolation coefficient in the coefficient image + //IndexType evaluateIndex; + long indx; + for (unsigned int l=0; lm_SplineOrder / 2; + evaluateIndex[l] = indx; + } + else { // Use this index calculation for even splineOrder + if (mSplineOrders[l] == 0) evaluateIndex[l] = (long)rint(x[l]); + else { + indx = (long)vcl_floor((x[l]+ 0.5)) - mSplineOrders[l] / 2; //this->m_SplineOrder / 2; + evaluateIndex[l] = indx; + } + } + } + + // Compute index of precomputed weights and get pointer to first weights + const IndexType weightIndex = GetSampleIndexOfPixelPosition(x, evaluateIndex); + *pweights = mWeightsCalculator.GetFirstTensorProduct(weightIndex); + + } + //==================================================================== + + + + +} //end namespace + +#endif //_CLITKVECTORBSPLINEINTERPOLATEIMAGEFUNCTIONWITHLUT_TXX diff --git a/itk/clitkVectorBSplineResampleImageFunction.h b/itk/clitkVectorBSplineResampleImageFunction.h new file mode 100644 index 0000000..73f99d8 --- /dev/null +++ b/itk/clitkVectorBSplineResampleImageFunction.h @@ -0,0 +1,69 @@ +#ifndef __clitkVectorBSplineResampleImageFunction_h +#define __clitkVectorBSplineResampleImageFunction_h + +#include "clitkVectorBSplineInterpolateImageFunction.h" + +namespace clitk +{ +/** \class VectorBSplineResampleImageFunction + * \brief Resample image intensity from a VectorBSpline coefficient image. + * + * This class resample the image intensity at a non-integer position + * from the input VectorBSpline coefficient image. + * + * Spline order may be from 0 to 5. + * + * In ITK, BSpline coefficient can be generated using a + * BSplineDecompositionImageFilter. Using this image function in + * conjunction with ResampleImageFunction allows the reconstruction + * of the original image at different resolution and size. + * + * \sa VectorBSplineInterpolateImageFunction + * \sa VectorBSplineDecompositionImageFilter + * \sa VectorResampleImageFilter + * + * \ingroup ImageFunctions + */ +template +class ITK_EXPORT VectorBSplineResampleImageFunction : + public VectorBSplineInterpolateImageFunction< + TImageType,TCoordRep,ITK_TYPENAME TImageType::PixelType::ValueType > +{ +public: + /** Standard class typedefs. */ + typedef VectorBSplineResampleImageFunction Self; + typedef VectorBSplineInterpolateImageFunction Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Run-time type information (and related methods). */ + itkTypeMacro(VectorBSplineResampleImageFunction, + VectorBSplineInterpolateImageFunction); + + /** New macro for creation of through a Smart Pointer */ + itkNewMacro( Self ); + + /** Set the input image representing the BSplineCoefficients */ + virtual void SetInputImage(const TImageType * inputData) + { + // bypass my superclass + this->itk::VectorInterpolateImageFunction::SetInputImage(inputData); + this->m_Coefficients = inputData; + if ( this->m_Coefficients.IsNotNull() ) + { + this->m_DataLength = this->m_Coefficients->GetBufferedRegion().GetSize(); + } + } + +protected: + VectorBSplineResampleImageFunction() {}; + virtual ~VectorBSplineResampleImageFunction() {}; + +private: + VectorBSplineResampleImageFunction(const Self&);//purposely not implemented +}; + +} // namespace clitk + + +#endif diff --git a/itk/clitkVectorBSplineResampleImageFunctionWithLUT.h b/itk/clitkVectorBSplineResampleImageFunctionWithLUT.h new file mode 100644 index 0000000..815add9 --- /dev/null +++ b/itk/clitkVectorBSplineResampleImageFunctionWithLUT.h @@ -0,0 +1,77 @@ +#ifndef __clitkVectorBSplineResampleImageFunctionWithLUT_h +#define __clitkVectorBSplineResampleImageFunctionWithLUT_h + +#include "clitkVectorBSplineInterpolateImageFunctionWithLUT.h" + +namespace clitk +{ +/** \class VectorBSplineResampleImageFunctionWithLUT + * \brief Resample image intensity from a VectorBSpline coefficient image using a LUT. + * + * This class resample the image intensity at a non-integer position + * from the input VectorBSpline coefficient image using a LUT. + * + * Spline order may be from 0 to 5. + * + * In ITK, VectorBSpline coefficient can be generated using a + * VectorBSplineDecompositionImageFilter. Using this image function in + * conjunction with ResampleImageFunction allows the reconstruction + * of the original image at different resolution and size. + * + * \sa VectorBSplineInterpolateImageFunctionWithLUT + * \sa VectorBSplineDecompositionImageFilter + * \sa ResampleImageFilter + * + * \ingroup ImageFunctions + */ +template +class ITK_EXPORT VectorBSplineResampleImageFunctionWithLUT : + public VectorBSplineInterpolateImageFunctionWithLUT< + TImageType,TCoordRep,ITK_TYPENAME TImageType::PixelType::ValueType > +{ +public: + /** Standard class typedefs. */ + typedef VectorBSplineResampleImageFunctionWithLUT Self; + typedef VectorBSplineInterpolateImageFunctionWithLUT< + TImageType,TCoordRep, ITK_TYPENAME TImageType::PixelType::ValueType > Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Run-time type information (and related methods). */ + itkTypeMacro(VectorBSplineReconstructionImageFunction, + VectorBSplineInterpolateImageFunctionWithLUT); + + /** New macro for creation of through a Smart Pointer */ + itkNewMacro( Self ); + + /** Set the input image representing the BSplineCoefficients */ + virtual void SetInputImage(const TImageType * inputData) + { + // bypass my superclass + this->itk::VectorInterpolateImageFunction::SetInputImage(inputData); + this->m_Coefficients = inputData; + if ( this->m_Coefficients.IsNotNull() ) + { + this->m_DataLength = this->m_Coefficients->GetBufferedRegion().GetSize(); + + // JV specific for BLUT ( contains the call to UpdatePrecomputedWeights() ) + this->UpdateWeightsProperties(); + } + } + +protected: + VectorBSplineResampleImageFunctionWithLUT() {}; + virtual ~VectorBSplineResampleImageFunctionWithLUT() {}; + void PrintSelf(std::ostream& os, itk::Indent indent) const + { + this->Superclass::PrintSelf( os, indent ); + } + +private: + VectorBSplineResampleImageFunctionWithLUT(const Self&);//purposely not implemented +}; + +} // namespace clitk + + +#endif diff --git a/itk/itkBSplineDecompositionImageFilterWithOBD.h b/itk/itkBSplineDecompositionImageFilterWithOBD.h new file mode 100644 index 0000000..3eb2471 --- /dev/null +++ b/itk/itkBSplineDecompositionImageFilterWithOBD.h @@ -0,0 +1,137 @@ +#ifndef __itkBSplineDecompositionImageFilterWithOBD_h +#define __itkBSplineDecompositionImageFilterWithOBD_h + +#include + +#include "itkImageLinearIteratorWithIndex.h" +#include "vnl/vnl_matrix.h" + +#include "itkImageToImageFilter.h" + +namespace itk +{ + +template +class ITK_EXPORT BSplineDecompositionImageFilterWithOBD : + public ImageToImageFilter +{ +public: + /** Standard class typedefs. */ + typedef BSplineDecompositionImageFilterWithOBD Self; + typedef ImageToImageFilter Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + /** Run-time type information (and related methods). */ + itkTypeMacro(BSplineDecompositionImageFilterWithOBD, itk::ImageToImageFilter); + + /** New macro for creation of through a Smart Pointer */ + itkNewMacro( Self ); + + /** Inherit input and output image types from Superclass. */ + typedef typename Superclass::InputImageType InputImageType; + typedef typename Superclass::InputImagePointer InputImagePointer; + typedef typename Superclass::InputImageConstPointer InputImageConstPointer; + typedef typename Superclass::OutputImagePointer OutputImagePointer; + + //JV add the size + typedef typename InputImageType::SizeType SizeType; + + /** Dimension underlying input image. */ + itkStaticConstMacro(ImageDimension, unsigned int,TInputImage::ImageDimension); + itkStaticConstMacro(OutputImageDimension, unsigned int, TOutputImage::ImageDimension); + + /** Iterator typedef support */ + typedef ImageLinearIteratorWithIndex OutputLinearIterator; + + /** Get/Sets the Spline Order, supports 0th - 5th order splines. The default + * is a 3rd order spline. */ + //JV only used to set the current order + void SetSplineOrder(unsigned int SplineOrder); + //JV Set the order by Dimension + void SetSplineOrders(SizeType); + + itkGetMacro(SplineOrder, int); + +#ifdef ITK_USE_CONCEPT_CHECKING + /** Begin concept checking */ + itkConceptMacro(DimensionCheck, + (Concept::SameDimension)); + itkConceptMacro(InputConvertibleToDoubleCheck, + (Concept::Convertible)); + itkConceptMacro(OutputConvertibleToDoubleCheck, + (Concept::Convertible)); + itkConceptMacro(InputConvertibleToOutputCheck, + (Concept::Convertible)); + itkConceptMacro(DoubleConvertibleToOutputCheck, + (Concept::Convertible)); + /** End concept checking */ +#endif + +protected: + BSplineDecompositionImageFilterWithOBD(); + virtual ~BSplineDecompositionImageFilterWithOBD() {}; + void PrintSelf(std::ostream& os, Indent indent) const; + + void GenerateData( ); + + /** This filter requires all of the input image. */ + void GenerateInputRequestedRegion(); + + /** This filter must produce all of its output at once. */ + void EnlargeOutputRequestedRegion( DataObject *output ); + + /** These are needed by the smoothing spline routine. */ + std::vector m_Scratch; // temp storage for processing of Coefficients + typename TInputImage::SizeType m_DataLength; // Image size + unsigned int m_SplineOrder; // User specified spline order (3rd or cubic is the default) + + //JV multiple splineOrders + SizeType m_SplineOrders; //SplineOrder by dimension + + double m_SplinePoles[3];// Poles calculated for a given spline order + int m_NumberOfPoles; // number of poles + double m_Tolerance; // Tolerance used for determining initial causal coefficient + unsigned int m_IteratorDirection; // Direction for iterator incrementing + + +private: + BSplineDecompositionImageFilterWithOBD( const Self& ); //purposely not implemented + void operator=( const Self& ); //purposely not implemented + + /** Determines the poles given the Spline Order. */ + virtual void SetPoles(); + + /** Converts a vector of data to a vector of Spline coefficients. */ + virtual bool DataToCoefficients1D(); + + /** Converts an N-dimension image of data to an equivalent sized image + * of spline coefficients. */ + void DataToCoefficientsND(); + + /** Determines the first coefficient for the causal filtering of the data. */ + virtual void SetInitialCausalCoefficient(double z); + + /** Determines the first coefficient for the anti-causal filtering of the data. */ + virtual void SetInitialAntiCausalCoefficient(double z); + + /** Used to initialize the Coefficients image before calculation. */ + void CopyImageToImage(); + + /** Copies a vector of data from the Coefficients image to the m_Scratch vector. */ + void CopyCoefficientsToScratch( OutputLinearIterator & ); + + /** Copies a vector of data from m_Scratch to the Coefficients image. */ + void CopyScratchToCoefficients( OutputLinearIterator & ); + +}; + + +} // namespace itk +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkBSplineDecompositionImageFilterWithOBD.txx" +#endif + +#endif + diff --git a/itk/itkBSplineDecompositionImageFilterWithOBD.txx b/itk/itkBSplineDecompositionImageFilterWithOBD.txx new file mode 100644 index 0000000..1ed152b --- /dev/null +++ b/itk/itkBSplineDecompositionImageFilterWithOBD.txx @@ -0,0 +1,421 @@ +#ifndef _itkBSplineDecompositionImageFilterWithOBD_txx +#define _itkBSplineDecompositionImageFilterWithOBD_txx + +#include "itkBSplineDecompositionImageFilterWithOBD.h" +#include "itkImageRegionConstIteratorWithIndex.h" +#include "itkImageRegionIterator.h" +#include "itkProgressReporter.h" +#include "itkVector.h" + +namespace itk +{ + +/** + * Constructor + */ +template +BSplineDecompositionImageFilterWithOBD +::BSplineDecompositionImageFilterWithOBD() +{ + m_SplineOrder = 0; + int SplineOrder = 3; + m_Tolerance = 1e-10; // Need some guidance on this one...what is reasonable? + m_IteratorDirection = 0; + this->SetSplineOrder(SplineOrder); +} + + +/** + * Standard "PrintSelf" method + */ +template +void +BSplineDecompositionImageFilterWithOBD +::PrintSelf( + std::ostream& os, + Indent indent) const +{ + Superclass::PrintSelf( os, indent ); + os << indent << "Spline Order: " << m_SplineOrder << std::endl; + +} + + +template +bool +BSplineDecompositionImageFilterWithOBD +::DataToCoefficients1D() +{ + + // See Unser, 1993, Part II, Equation 2.5, + // or Unser, 1999, Box 2. for an explaination. + + double c0 = 1.0; + + if (m_DataLength[m_IteratorDirection] == 1) //Required by mirror boundaries + { + return false; + } + + // Compute overall gain + for (int k = 0; k < m_NumberOfPoles; k++) + { + // Note for cubic splines lambda = 6 + c0 = c0 * (1.0 - m_SplinePoles[k]) * (1.0 - 1.0 / m_SplinePoles[k]); + } + + // apply the gain + for (unsigned int n = 0; n < m_DataLength[m_IteratorDirection]; n++) + { + m_Scratch[n] *= c0; + } + + // loop over all poles + for (int k = 0; k < m_NumberOfPoles; k++) + { + // causal initialization + this->SetInitialCausalCoefficient(m_SplinePoles[k]); + // causal recursion + for (unsigned int n = 1; n < m_DataLength[m_IteratorDirection]; n++) + { + m_Scratch[n] += m_SplinePoles[k] * m_Scratch[n - 1]; + } + + // anticausal initialization + this->SetInitialAntiCausalCoefficient(m_SplinePoles[k]); + // anticausal recursion + for ( int n = m_DataLength[m_IteratorDirection] - 2; 0 <= n; n--) + { + m_Scratch[n] = m_SplinePoles[k] * (m_Scratch[n + 1] - m_Scratch[n]); + } + } + return true; + +} + + +template +void +BSplineDecompositionImageFilterWithOBD +::SetSplineOrder(unsigned int SplineOrder) +{ + if (SplineOrder == m_SplineOrder) + { + return; + } + m_SplineOrder = SplineOrder; + this->SetPoles(); + this->Modified(); + +} + +//JV +template +void +BSplineDecompositionImageFilterWithOBD +::SetSplineOrders(SizeType SplineOrders) +{ + m_SplineOrders=SplineOrders; +} + +template +void +BSplineDecompositionImageFilterWithOBD +::SetPoles() +{ + /* See Unser, 1997. Part II, Table I for Pole values */ + // See also, Handbook of Medical Imaging, Processing and Analysis, Ed. Isaac N. Bankman, + // 2000, pg. 416. + switch (m_SplineOrder) + { + + case 3: + m_NumberOfPoles = 1; + m_SplinePoles[0] = vcl_sqrt(3.0) - 2.0; + break; + case 0: + m_NumberOfPoles = 0; + break; + case 1: + m_NumberOfPoles = 0; + break; + case 2: + m_NumberOfPoles = 1; + m_SplinePoles[0] = vcl_sqrt(8.0) - 3.0; + break; + case 4: + m_NumberOfPoles = 2; + m_SplinePoles[0] = vcl_sqrt(664.0 - vcl_sqrt(438976.0)) + vcl_sqrt(304.0) - 19.0; + m_SplinePoles[1] = vcl_sqrt(664.0 + vcl_sqrt(438976.0)) - vcl_sqrt(304.0) - 19.0; + break; + case 5: + m_NumberOfPoles = 2; + m_SplinePoles[0] = vcl_sqrt(135.0 / 2.0 - vcl_sqrt(17745.0 / 4.0)) + vcl_sqrt(105.0 / 4.0) + - 13.0 / 2.0; + m_SplinePoles[1] = vcl_sqrt(135.0 / 2.0 + vcl_sqrt(17745.0 / 4.0)) - vcl_sqrt(105.0 / 4.0) + - 13.0 / 2.0; + break; + default: + // SplineOrder not implemented yet. + ExceptionObject err(__FILE__, __LINE__); + err.SetLocation( ITK_LOCATION); + err.SetDescription( "SplineOrder must be between 0 and 5. Requested spline order has not been implemented yet." ); + throw err; + break; + } +} + + +template +void +BSplineDecompositionImageFilterWithOBD +::SetInitialCausalCoefficient(double z) +{ + /* begining InitialCausalCoefficient */ + /* See Unser, 1999, Box 2 for explaination */ + + double sum, zn, z2n, iz; + unsigned long horizon; + + /* this initialization corresponds to mirror boundaries */ + horizon = m_DataLength[m_IteratorDirection]; + zn = z; + if (m_Tolerance > 0.0) + { + horizon = (long)vcl_ceil(log(m_Tolerance) / vcl_log(fabs(z))); + } + if (horizon < m_DataLength[m_IteratorDirection]) + { + /* accelerated loop */ + sum = m_Scratch[0]; // verify this + for (unsigned int n = 1; n < horizon; n++) + { + sum += zn * m_Scratch[n]; + zn *= z; + } + m_Scratch[0] = sum; + } + else { + /* full loop */ + iz = 1.0 / z; + z2n = vcl_pow(z, (double)(m_DataLength[m_IteratorDirection] - 1L)); + sum = m_Scratch[0] + z2n * m_Scratch[m_DataLength[m_IteratorDirection] - 1L]; + z2n *= z2n * iz; + for (unsigned int n = 1; n <= (m_DataLength[m_IteratorDirection] - 2); n++) + { + sum += (zn + z2n) * m_Scratch[n]; + zn *= z; + z2n *= iz; + } + m_Scratch[0] = sum / (1.0 - zn * zn); + } +} + + +template +void +BSplineDecompositionImageFilterWithOBD +::SetInitialAntiCausalCoefficient(double z) +{ + // this initialization corresponds to mirror boundaries + /* See Unser, 1999, Box 2 for explaination */ + // Also see erratum at http://bigwww.epfl.ch/publications/unser9902.html + m_Scratch[m_DataLength[m_IteratorDirection] - 1] = + (z / (z * z - 1.0)) * + (z * m_Scratch[m_DataLength[m_IteratorDirection] - 2] + m_Scratch[m_DataLength[m_IteratorDirection] - 1]); +} + + +template +void +BSplineDecompositionImageFilterWithOBD +::DataToCoefficientsND() +{ + OutputImagePointer output = this->GetOutput(); + + Size size = output->GetBufferedRegion().GetSize(); + + unsigned int count = output->GetBufferedRegion().GetNumberOfPixels() / size[0] * ImageDimension; + + ProgressReporter progress(this, 0, count, 10); + + // Initialize coeffient array + this->CopyImageToImage(); // Coefficients are initialized to the input data + + for (unsigned int n=0; n < ImageDimension; n++) + { + m_IteratorDirection = n; + // Loop through each dimension + + //JV Set the correct order by dimension! + SetSplineOrder(m_SplineOrders[n]); + + // Initialize iterators + OutputLinearIterator CIterator( output, output->GetBufferedRegion() ); + CIterator.SetDirection( m_IteratorDirection ); + // For each data vector + while ( !CIterator.IsAtEnd() ) + { + // Copy coefficients to scratch + this->CopyCoefficientsToScratch( CIterator ); + + // Perform 1D BSpline calculations + this->DataToCoefficients1D(); + + // Copy scratch back to coefficients. + // Brings us back to the end of the line we were working on. + CIterator.GoToBeginOfLine(); + this->CopyScratchToCoefficients( CIterator ); // m_Scratch = m_Image; + CIterator.NextLine(); + progress.CompletedPixel(); + } + } +} + + +/** + * Copy the input image into the output image + */ +template +void +BSplineDecompositionImageFilterWithOBD +::CopyImageToImage() +{ + + typedef ImageRegionConstIteratorWithIndex< TInputImage > InputIterator; + typedef ImageRegionIterator< TOutputImage > OutputIterator; + typedef typename TOutputImage::PixelType OutputPixelType; + + InputIterator inIt( this->GetInput(), this->GetInput()->GetBufferedRegion() ); + OutputIterator outIt( this->GetOutput(), this->GetOutput()->GetBufferedRegion() ); + + inIt = inIt.Begin(); + outIt = outIt.Begin(); + + while ( !outIt.IsAtEnd() ) + { + outIt.Set( static_cast( inIt.Get() ) ); + ++inIt; + ++outIt; + } + +} + + +/** + * Copy the scratch to one line of the output image + */ +template +void +BSplineDecompositionImageFilterWithOBD +::CopyScratchToCoefficients(OutputLinearIterator & Iter) +{ + typedef typename TOutputImage::PixelType OutputPixelType; + unsigned long j = 0; + while ( !Iter.IsAtEndOfLine() ) + { + Iter.Set( static_cast( m_Scratch[j] ) ); + ++Iter; + ++j; + } + +} + + +/** + * Copy one line of the output image to the scratch + */ +template +void +BSplineDecompositionImageFilterWithOBD +::CopyCoefficientsToScratch(OutputLinearIterator & Iter) +{ + unsigned long j = 0; + while ( !Iter.IsAtEndOfLine() ) + { + m_Scratch[j] = static_cast( Iter.Get() ) ; + ++Iter; + ++j; + } +} + + +/** + * GenerateInputRequestedRegion method. + */ +template +void +BSplineDecompositionImageFilterWithOBD +::GenerateInputRequestedRegion() +{ + // this filter requires the all of the input image to be in + // the buffer + InputImagePointer inputPtr = const_cast< TInputImage * > ( this->GetInput() ); + if( inputPtr ) + { + inputPtr->SetRequestedRegionToLargestPossibleRegion(); + } +} + + +/** + * EnlargeOutputRequestedRegion method. + */ +template +void +BSplineDecompositionImageFilterWithOBD +::EnlargeOutputRequestedRegion( + DataObject *output ) +{ + + // this filter requires the all of the output image to be in + // the buffer + TOutputImage *imgData; + imgData = dynamic_cast( output ); + if( imgData ) + { + imgData->SetRequestedRegionToLargestPossibleRegion(); + } + +} + +/** + * Generate data + */ +template +void +BSplineDecompositionImageFilterWithOBD +::GenerateData() +{ + + // Allocate scratch memory + InputImageConstPointer inputPtr = this->GetInput(); + m_DataLength = inputPtr->GetBufferedRegion().GetSize(); + + unsigned long maxLength = 0; + for ( unsigned int n = 0; n < ImageDimension; n++ ) + { + if ( m_DataLength[n] > maxLength ) + { + maxLength = m_DataLength[n]; + } + } + m_Scratch.resize( maxLength ); + + // Allocate memory for output image + OutputImagePointer outputPtr = this->GetOutput(); + outputPtr->SetBufferedRegion( outputPtr->GetRequestedRegion() ); + outputPtr->Allocate(); + + // Calculate actual output + this->DataToCoefficientsND(); + + // Clean up + m_Scratch.clear(); + +} + + +} // namespace itk + +#endif diff --git a/itk/itkBSplineInterpolateImageFunctionWithLUT.h b/itk/itkBSplineInterpolateImageFunctionWithLUT.h new file mode 100644 index 0000000..85b3436 --- /dev/null +++ b/itk/itkBSplineInterpolateImageFunctionWithLUT.h @@ -0,0 +1,134 @@ +#ifndef ITKBSPLINEINTERPOLATEIMAGEFUNCTIONWITHLUT_H +#define ITKBSPLINEINTERPOLATEIMAGEFUNCTIONWITHLUT_H + +/* ========================================================================= + + @file itkBSplineInterpolateImageFunctionWithLUT.h + @author David Sarrut + + Copyright (c) + * CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). + All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + * Léon Bérard cancer center, 28 rue Laënnec, 69373 Lyon cedex 08, France + * http://www.creatis.insa-lyon.fr/rio + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +========================================================================= */ + +#include "itkBSplineWeightsCalculator.h" +//#include "clitkTimer.h" +#include + +namespace itk { + + template < + class TImageType, + class TCoordRep = double, + class TCoefficientType = double > + class ITK_EXPORT BSplineInterpolateImageFunctionWithLUT : + public itk::BSplineInterpolateImageFunction { + + public: + /** Class typedefs */ + typedef BSplineInterpolateImageFunctionWithLUT Self; + typedef BSplineInterpolateImageFunction Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + typedef typename Superclass::OutputType OutputType; + typedef typename Superclass::ContinuousIndexType ContinuousIndexType; + typedef typename TImageType::IndexType IndexType; + typedef typename TImageType::IndexValueType IndexValueType; + typedef typename TImageType::SizeType SizeType; + typedef typename TImageType::SpacingType SpacingType; + + /** New macro for creation of through a Smart Pointer */ + itkNewMacro(Self); + + /** Setting LUT sampling (one parameters by dimension or a single + one for all dim); Default is 10 (for each dim) **/ + void SetLUTSamplingFactor(const int& s); + void SetLUTSamplingFactors(const SizeType& s); + + /** Get/Sets the Spline Order, supports 0th - 5th order + * splines. The default is a 3rd order spline. */ + void SetSplineOrder(const unsigned int & SplineOrder); + + //JV this is added to support different degrees over each dimension + void SetSplineOrders(const SizeType & SplineOrders); + + /** Set the input image. This must be set by the user. */ + virtual void SetInputImage(const TImageType * inputData); + //void SetOutputSpacing(const SpacingType & s); + //void SetInputImageIsCoefficient(bool inputIsCoef) { mInputIsCoef = inputIsCoef; } + + /** Evaluate the function at a ContinuousIndex position. + Overwritten for taking LUT into account */ + virtual OutputType EvaluateAtContinuousIndex(const ContinuousIndexType & index ) const; + + /** Static convenient functions to compute BSpline weights for + various order, dimension, sampling ... **/ + static void ComputeBlendingWeights(int dim, int order, int sampling, TCoefficientType * weights); + + /** Timer giving computation time for coefficients computation **/ + // const clitk::Timer & GetCoefTimer() const { return mCoefficientTimer; } + + /** Get estimated error **/ + + double GetIntrinsicError() const { return *mIntrinsecError; } + long GetNumberOfError() const { return *mNumberOfError; } + double GetIntrinsicErrorMax() const { return *mIntrinsecErrorMax; } + + protected: + BSplineInterpolateImageFunctionWithLUT(); + ~BSplineInterpolateImageFunctionWithLUT(){;} + + SizeType mSupport; // nb of coef values used for interpolation (order+1) in 1 dimension + SizeType mHalfSupport; // half size of the previous + unsigned int mSupportSize; // Total support size for all dimension + std::vector mSupportOffset; // Memory pointer offset for going from one coef position to the other (inside the whole support) + std::vector mSupportIndex; // nD Index of all support values + IndexType mInputMemoryOffset; // Memory dimension offsets for input image + + /** Sampling factors for LUT weights **/ + SizeType mSamplingFactors; + bool mWeightsAreUpToDate; + //SpacingType mOutputSpacing; + + double * mIntrinsecError; + double * mIntrinsecErrorMax; + long * mNumberOfError; + + //JV add iscoeff, and splineorders + // bool mInputIsCoef; + SizeType mSplineOrders; + + // Filter to compute weights + itk::BSplineWeightsCalculator mWeightsCalculator; + + // Convenient functions + void UpdatePrecomputedWeights(); + void UpdateWeightsProperties(); + IndexType GetSampleIndexOfPixelPosition(const ContinuousIndexType & x, IndexType & EvaluateIndex) const; + + // Timing options + // clitk::Timer mCoefficientTimer; + // clitk::Timer mLUTTimer; + bool mTimerEnabled; + + //JV threadsafety: everything on the stack + //std::vector mCorrectedSupportOffset; + //std::vector mCorrectedSupportIndex; + TCoefficientType * coef; + + }; // end class itkBSplineInterpolateImageFunctionWithLUT +} // end namespace + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkBSplineInterpolateImageFunctionWithLUT.txx" +#endif + +#endif /* end #define ITKBSPLINEINTERPOLATEIMAGEFUNCTIONWITHLUT_H */ diff --git a/itk/itkBSplineInterpolateImageFunctionWithLUT.h.original b/itk/itkBSplineInterpolateImageFunctionWithLUT.h.original new file mode 100644 index 0000000..1f92e50 --- /dev/null +++ b/itk/itkBSplineInterpolateImageFunctionWithLUT.h.original @@ -0,0 +1,132 @@ +/* ========================================================================= + + @file itkBSplineInterpolateImageFunctionWithLUT.h + @author David Sarrut + + Copyright (c) + * CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). + All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + * Léon Bérard cancer center, 28 rue Laënnec, 69373 Lyon cedex 08, France + * http://www.creatis.insa-lyon.fr/rio + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +========================================================================= */ + +#ifndef ITKBSPLINEINTERPOLATEIMAGEFUNCTIONWITHLUT_H +#define ITKBSPLINEINTERPOLATEIMAGEFUNCTIONWITHLUT_H +#include "itkCastImageFilter.h" +#include "itkBSplineWeightsCalculator.h" +//#include "clitkTimer.h" + +#include + +namespace itk { + + template < + class TImageType, + class TCoordRep = double, + class TCoefficientType = double > + class ITK_EXPORT BSplineInterpolateImageFunctionWithLUT : + public itk::BSplineInterpolateImageFunction { + + public: + /** Class typedefs */ + typedef BSplineInterpolateImageFunctionWithLUT Self; + typedef BSplineInterpolateImageFunction Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + typedef typename Superclass::OutputType OutputType; + typedef typename Superclass::ContinuousIndexType ContinuousIndexType; + typedef typename TImageType::IndexType IndexType; + typedef typename TImageType::IndexValueType IndexValueType; + typedef typename TImageType::SizeType SizeType; + typedef typename TImageType::SpacingType SpacingType; + + /** New macro for creation of through a Smart Pointer */ + itkNewMacro(Self); + BSplineInterpolateImageFunctionWithLUT(); + + /** Setting LUT sampling (one parameters by dimension or a single + one for all dim); Default is 10 (for each dim) **/ + void SetLUTSamplingFactor(int s); + void SetLUTSamplingFactors(int * s); + + /** Get/Sets the Spline Order, supports 0th - 5th order + * splines. The default is a 3rd order spline. */ + void SetSplineOrder(unsigned int SplineOrder); + + //JV this is added to support different degrees over each dimension + void SetSplineOrders( SizeType SplineOrders); + + /** Set the input image. This must be set by the user. */ + virtual void SetInputImage(const TImageType * inputData); + void SetOutputSpacing(const SpacingType & s); + void SetInputImageIsCoefficient(bool inputIsCoef) { mInputIsCoef = inputIsCoef; } + + /** Evaluate the function at a ContinuousIndex position. + Overwritten for taking LUT into account */ + virtual OutputType EvaluateAtContinuousIndex(const ContinuousIndexType & index ) const; + + /** Static convenient functions to compute BSpline weights for + various order, dimension, sampling ... **/ + static void ComputeBlendingWeights(int dim, int order, int sampling, TCoefficientType * weights); + + /** Timer giving computation time for coefficients computation **/ + // const clitk::Timer & GetCoefTimer() const { return mCoefficientTimer; } + + /** Get estimated error **/ + + double GetIntrinsicError() const { return *mIntrinsecError; } + long GetNumberOfError() const { return *mNumberOfError; } + double GetIntrinsicErrorMax() const { return *mIntrinsecErrorMax; } + + protected: + SizeType mSupport; // nb of coef values used for interpolation (order+1) in 1 dimension + SizeType mHalfSupport; // half size of the previous + unsigned int mSupportSize; // Total support size for all dimension + std::vector mSupportOffset; // Memory pointer offset for going from one coef position to the other (inside the whole support) + std::vector mSupportIndex; // nD Index of all support values + IndexType mInputMemoryOffset; // Memory dimension offsets for input image + + /** Sampling factors for LUT weights **/ + SizeType mSamplingFactors; + bool mWeightsAreUpToDate; + SpacingType mOutputSpacing; + + double * mIntrinsecError; + double * mIntrinsecErrorMax; + long * mNumberOfError; + + //JV add iscoeff, and splineorders + bool mInputIsCoef; + SizeType mSplineOrders; + + // Filter to compute weights + itk::BSplineWeightsCalculator mWeightsCalculator; + + // Convenient functions + void UpdatePrecomputedWeights(); + IndexType GetSampleIndexOfPixelPosition(const ContinuousIndexType & x, IndexType & EvaluateIndex) const; + + // Timing options + // clitk::Timer mCoefficientTimer; + // clitk::Timer mLUTTimer; + bool mTimerEnabled; + + std::vector mCorrectedSupportOffset; + TCoefficientType * coef; + + std::vector mCorrectedSupportIndex; + + }; // end class itkBSplineInterpolateImageFunctionWithLUT + +#include "itkBSplineInterpolateImageFunctionWithLUT.txx" + +} // end namespace + +#endif /* end #define ITKBSPLINEINTERPOLATEIMAGEFUNCTIONWITHLUT_H */ + diff --git a/itk/itkBSplineInterpolateImageFunctionWithLUT.txx b/itk/itkBSplineInterpolateImageFunctionWithLUT.txx new file mode 100644 index 0000000..275bc53 --- /dev/null +++ b/itk/itkBSplineInterpolateImageFunctionWithLUT.txx @@ -0,0 +1,395 @@ +#ifndef _ITKINTERPOLATEIMAGEFUNCTIONWITHLUT_TXX +#define _ITKINTERPOLATEIMAGEFUNCTIONWITHLUT_TXX + +/* ========================================================================= + +@file itkBSplineInterpolateImageFunctionWithLUT.txx +@author David Sarrut + +Copyright (c) +* CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). +All rights reserved. See Doc/License.txt or +http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. +* Léon Bérard cancer center, 28 rue Laënnec, 69373 Lyon cedex 08, France +* http://www.creatis.insa-lyon.fr/rio + +This software is distributed WITHOUT ANY WARRANTY; without even the +implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +========================================================================= */ +namespace itk +{ + //==================================================================== + template + BSplineInterpolateImageFunctionWithLUT:: + BSplineInterpolateImageFunctionWithLUT():Superclass() { + // Set default values + //for(int i=0; i + void BSplineInterpolateImageFunctionWithLUT:: + SetLUTSamplingFactor(const int& s) { + for(int i=0; i + void BSplineInterpolateImageFunctionWithLUT:: + SetLUTSamplingFactors(const SizeType& s) { + for(int i=0; i + // void BSplineInterpolateImageFunctionWithLUT:: + // SetOutputSpacing(const SpacingType & s) { + // for(int i=0; i + void BSplineInterpolateImageFunctionWithLUT:: + SetSplineOrder(const unsigned int& SplineOrder) { + Superclass::SetSplineOrder(SplineOrder); + // Compute support and half size + static const int d = TImageType::ImageDimension; + for(int l=0; l + void BSplineInterpolateImageFunctionWithLUT:: + SetSplineOrders(const SizeType& SplineOrders) { + mSplineOrders=SplineOrders; + + // Compute support and half size + static const int d = TImageType::ImageDimension; + for(int l=0; l + void BSplineInterpolateImageFunctionWithLUT:: + SetInputImage(const TImageType * inputData) { + + //============================== + // if (!mInputIsCoef) + // { + Superclass::SetInputImage(inputData); + // } + + //============================== + // //JV Don't call superclass (decomposition filter is executeed each time!) + // else + // { + // this->m_Coefficients = inputData; + // if ( this->m_Coefficients.IsNotNull()) + // { + // this->m_DataLength = this->m_Coefficients->GetBufferedRegion().GetSize(); + // } + + // //Call super-superclass in case more input arrives + // itk::ImageFunction::RealType, TCoefficientType>::SetInputImage(inputData); + // } + if (!inputData) return; + UpdateWeightsProperties(); + + } + + //==================================================================== + template + void BSplineInterpolateImageFunctionWithLUT:: + UpdateWeightsProperties() { + + // Compute Memory offset inside coefficients images (for looping over coefficients) + static const unsigned int d = TImageType::ImageDimension; + mInputMemoryOffset[0] = 1; + for(unsigned int l=1; lm_Coefficients->GetLargestPossibleRegion().GetSize(l-1); + } + + //JV Put here? + if (!mWeightsAreUpToDate) + { + // Compute mSupportOffset according to input size + mSupportOffset.resize(mSupportSize); + mSupportIndex.resize(mSupportSize); + for(unsigned int l=0; l(mSupportIndex[k], mInputMemoryOffset); + // next coefficient index + if (k != mSupportSize-1) { + for(unsigned int l=0; l(mSupportIndex[k+1][l]) == mSupport[l]) { + mSupportIndex[k+1][l] = 0; + l++; + } + else stop = true; + } + } + } + + // // Check + // for(unsigned int l=0; l + void BSplineInterpolateImageFunctionWithLUT:: + UpdatePrecomputedWeights() { + // mLUTTimer.Reset(); + // mLUTTimer.Start(); + mWeightsCalculator.SetSplineOrders(mSplineOrders); + mWeightsCalculator.SetSamplingFactors(mSamplingFactors); + mWeightsCalculator.ComputeTensorProducts(); + mWeightsAreUpToDate = true; + //DS + // coef = new TCoefficientType[mSupportSize]; + // mCorrectedSupportIndex.resize(mSupportSize); + // mCorrectedSupportOffset.resize(mSupportSize); + // mLUTTimer.Stop(); + // mLUTTimer.Print("LUT \t"); + } + //==================================================================== + + //==================================================================== + template + typename BSplineInterpolateImageFunctionWithLUT::IndexType + BSplineInterpolateImageFunctionWithLUT:: + GetSampleIndexOfPixelPosition(const ContinuousIndexType & x, IndexType & EvaluateIndex) const { + + /* + WARNING : sometimes, a floating number x could not really be + represented in memory. In this case, the difference between x and + floor(x) can be almost 1 (instead of 0). So we take into account + such special case, otherwise it could lead to annoying results. + */ + // static const TCoefficientType tiny = 1.0e-7; + IndexType index; + + for(int l=0; l *mIntrinsecErrorMax) *mIntrinsecErrorMax = fabs(index[l]-t2); + */ + + // When to close to 1, take the next coefficient for odd order, but + // only change index for odd + if (index[l] == (int)mSamplingFactors[l]) { + index[l] = 0; + if (mSplineOrders[l] & 1) EvaluateIndex[l] = EvaluateIndex[l]+1; + } + } + + // The end + return index; + } + + + //==================================================================== + + //==================================================================== + template + typename BSplineInterpolateImageFunctionWithLUT::OutputType + BSplineInterpolateImageFunctionWithLUT:: + EvaluateAtContinuousIndex(const ContinuousIndexType & x) const { + + // For shorter coding + static const unsigned int d = TImageType::ImageDimension; + + // Compute the index of the first interpolation coefficient in the coefficient image + IndexType evaluateIndex; + long indx; + for (unsigned int l=0; lm_SplineOrder / 2; + evaluateIndex[l] = indx; + } + else { // Use this index calculation for even splineOrder + if (mSplineOrders[l] == 0) evaluateIndex[l] = (long)rint(x[l]); + else { + indx = (long)vcl_floor((x[l]+ 0.5)) - mSplineOrders[l] / 2; //this->m_SplineOrder / 2; + evaluateIndex[l] = indx; + } + } + } + + // Compute index of precomputed weights and get pointer to first weights + const IndexType weightIndex = GetSampleIndexOfPixelPosition(x, evaluateIndex); + const TCoefficientType * pweights = mWeightsCalculator.GetFirstTensorProduct(weightIndex); + + // Check boundaries + bool boundaryCase = false; + for (unsigned int l=0; l= this->m_Coefficients->GetLargestPossibleRegion().GetSize(l)) { + boundaryCase = true; + } + } + + // Pointer to support offset + const int * psupport; + + // Special case for boundary (to be changed ....) + std::vector correctedSupportOffset; + if (boundaryCase) { + // return -1000; + //std::vector coef(mSupportSize); + // DD(EvaluateIndex); + //std::vector CorrectedSupportOffset;//(mSupportSize); + std::vector correctedSupportIndex;//(mSupportSize); + correctedSupportIndex.resize(mSupportSize); + correctedSupportOffset.resize(mSupportSize); + for(unsigned int i=0; im_Coefficients->GetLargestPossibleRegion().GetSize(l); + // DD(a); + // DD(b); + long d2 = 2 * b - 2; + if (a < 0) { + correctedSupportIndex[i][l] = -a - d2*(-a/d2) - evaluateIndex[l];//mSupportIndex[i][l]-a; + } + else { + if (a>=b) { + correctedSupportIndex[i][l] = d2 - a - evaluateIndex[l]; + } + else { + correctedSupportIndex[i][l] = mSupportIndex[i][l]; //a - d2*(a/d2) - EvaluateIndex[l]; + } + /* + if (a>=b) { + correctedSupportIndex[i][l] = d2 - a - EvaluateIndex[l];//mSupportIndex[i][l] - (a-(b-1)); + } + else { + correctedSupportIndex[i][l] = mSupportIndex[i][l]; + } + */ + } + } + // DD(correctedSupportIndex[i]); + correctedSupportOffset[i] = itk::Index2Offset(correctedSupportIndex[i], mInputMemoryOffset); + } + // for (unsigned int l=0; lm_Coefficients->GetPixel(evaluateIndex)); + + // Main loop over BSpline support + TCoefficientType interpolated = 0.0; + for (unsigned int p=0; p + + Copyright (c) + * CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). + All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + * L�on B�rard cancer center, 28 rue La�nnec, 69373 Lyon cedex 08, France + * http://www.creatis.insa-lyon.fr/rio + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +========================================================================= */ +#include "itkCastImageFilter.h" + +//==================================================================== +template +BSplineInterpolateImageFunctionWithLUT:: +BSplineInterpolateImageFunctionWithLUT():Superclass() { + // Set default values + for(int i=0; i +void BSplineInterpolateImageFunctionWithLUT:: +SetLUTSamplingFactor(int s) { + for(int i=0; i +void BSplineInterpolateImageFunctionWithLUT:: +SetOutputSpacing(const SpacingType & s) { + for(int i=0; i +void BSplineInterpolateImageFunctionWithLUT:: +SetSplineOrder(unsigned int SplineOrder) { + Superclass::SetSplineOrder(SplineOrder); + // Compute support and half size + static const int d = TImageType::ImageDimension; + for(int l=0; l +void BSplineInterpolateImageFunctionWithLUT:: +SetSplineOrders(SizeType SplineOrders) { + mSplineOrders=SplineOrders; + DD(mSplineOrders); +// Compute support and half size + static const int d = TImageType::ImageDimension; + for(int l=0; l +void BSplineInterpolateImageFunctionWithLUT:: +SetInputImage(const TImageType * inputData) { + + // Call superclass SetInputImage and return if input is null + // clitk::Timer t; + // t.Start(); + //ds + // this->InterpolateImageFunction::SetInputImage(inputData); + + //============================== + if (!mInputIsCoef) { + Superclass::SetInputImage(inputData); + // t.Stop(); + } + //============================== + else { + // If inputData is not float/double, we do not want to set + // mInputIsCoef to true, but the compiler goes here ... + + if (typeid(typename TImageType::PixelType) != typeid(TCoefficientType)) { + std::cerr << "Input should be float or double to be set as 'coefficients' with SetInputImageIsCoefficient(true) and should be the same type than TCoefficientType" << std::endl; + exit(0); + } + else { + itkStaticConstMacro(ImageDimension, unsigned int, Superclass::ImageDimension); + typedef Image CoefficientImageType; + typedef itk::CastImageFilter< TImageType, CoefficientImageType> CastFilterType; + typename CastFilterType::Pointer castFilter=CastFilterType::New(); + castFilter->SetInput(inputData); + castFilter->Update(); + this->m_Coefficients=castFilter->GetOutput(); + if ( this->m_Coefficients.IsNotNull()) + this->m_DataLength = this->m_Coefficients->GetBufferedRegion().GetSize(); + } + +// //JV input should be double or float. To keep it generic: cast to the CoefficientImageType +// /** Dimension underlying input image. */ +// itkStaticConstMacro(ImageDimension, unsigned int, Superclass::ImageDimension); +// /** Internal Coefficient typedef support */ +// DD( ImageDimension); +// typedef Image CoefficientImageType; +// typedef itk::CastImageFilter< TImageType, CoefficientImageType> CastFilterType; +// typename CastFilterType::Pointer castFilter=CastFilterType::New(); +// castFilter->SetInput(inputData); +// castFilter->Update(); +// DS this->InterpolateImageFunction::m_Coefficients = inputData; + +// //JV cast to the coeff type, don't tell my mother +// this->InterpolateImageFunction::SetInputImage(inputData); +// this->m_Coefficients=castFilter->GetOutput(); +// DS ?????? this->m_Coefficients = inputData; + +// // //============================== old not generic solution +// // this->InterpolateImageFunction::SetInputImage(inputData); +// // DS this->InterpolateImageFunction::m_Coefficients = inputData; +// // this->m_Coefficients = inputData; +// // //============================== +// if ( this->m_Coefficients.IsNotNull()) { +// this->m_DataLength = this->m_Coefficients->GetBufferedRegion().GetSize(); +// } + } + + // t.Stop(); + if (!inputData) return; + // mCoefficientTimer = t; + + // Compute Memory offset inside coefficients images (for looping over coefficients) + static const int d = TImageType::ImageDimension; + mInputMemoryOffset[0] = 1; + for(int l=1; lm_Coefficients->GetLargestPossibleRegion().GetSize(l-1); + } + + // Compute mSupportOffset according to input size + mSupportOffset.resize(mSupportSize); + mSupportIndex.resize(mSupportSize); + for(int l=0; l(mSupportIndex[k], mInputMemoryOffset); + // next coefficient index + if (k != mSupportSize-1) { + for(int l=0; l +void BSplineInterpolateImageFunctionWithLUT:: +UpdatePrecomputedWeights() { +// mLUTTimer.Reset(); +// mLUTTimer.Start(); + mWeightsCalculator.SetSplineOrders(mSplineOrders); + mWeightsCalculator.SetSamplingFactors(mSamplingFactors); + mWeightsCalculator.ComputeTensorProducts(); + mWeightsAreUpToDate = true; + //DS + // coef = new TCoefficientType[mSupportSize]; + // mCorrectedSupportIndex.resize(mSupportSize); + // mCorrectedSupportOffset.resize(mSupportSize); + // mLUTTimer.Stop(); +// mLUTTimer.Print("LUT \t"); +} +//==================================================================== + +//==================================================================== +template +typename BSplineInterpolateImageFunctionWithLUT::IndexType +BSplineInterpolateImageFunctionWithLUT:: +GetSampleIndexOfPixelPosition(const ContinuousIndexType & x, IndexType & EvaluateIndex) const { + + /* + WARNING : sometimes, a floating number x could not really be + represented in memory. In this case, the difference between x and + floor(x) can be almost 1 (instead of 0). So we take into account + such special case, otherwise it could lead to annoying results. + */ + // static const TCoefficientType tiny = 1.0e-7; + IndexType index; + + for(int l=0; l *mIntrinsecErrorMax) *mIntrinsecErrorMax = fabs(index[l]-t2); + */ + + // When to close to 1, take the next coefficient for ordd order, but + // only change index for odd + if (index[l] == (int)mSamplingFactors[l]) { + index[l] = 0; + if (mSplineOrders[l] & 1) EvaluateIndex[l] = EvaluateIndex[l]+1; + } + } + + // The end + return index; +} +//==================================================================== + +//==================================================================== +template +typename BSplineInterpolateImageFunctionWithLUT::OutputType +BSplineInterpolateImageFunctionWithLUT:: +EvaluateAtContinuousIndex(const ContinuousIndexType & x) const { + + // For shorter coding + static const unsigned int d = TImageType::ImageDimension; + + // Compute the indexe of the first interpolation coefficient in the + // coefficient image + IndexType EvaluateIndex; + long indx; + for (unsigned int l=0; lm_SplineOrder / 2; + EvaluateIndex[l] = indx; + } + else { // Use this index calculation for even splineOrder + if (mSplineOrders[l] == 0) EvaluateIndex[l] = (long)rint(x[l]); + else { + indx = (long)vcl_floor((x[l]+ 0.5)) - mSplineOrders[l] / 2; //this->m_SplineOrder / 2; + EvaluateIndex[l] = indx; + } + } + } + + // Compute index of precomputed weights and get pointer to first weights + const IndexType weightIndex = GetSampleIndexOfPixelPosition(x, EvaluateIndex); + const TCoefficientType * pweights = mWeightsCalculator.GetFirstTensorProduct(weightIndex); + + // Check boundaries + bool mBoundaryCase = false; + for (unsigned int l=0; l= this->m_Coefficients->GetLargestPossibleRegion().GetSize(l)) { + mBoundaryCase = true; + } + } + + // Pointer to support offset + const int * psupport; + + // Special case for boundary (to be changed ....) + std::vector mCorrectedSupportOffset;//(mSupportSize); + if (mBoundaryCase) { + // return -1000; + //std::vector coef(mSupportSize); + // DD(EvaluateIndex); + std::vector mCorrectedSupportIndex;//(mSupportSize); + mCorrectedSupportIndex.resize(mSupportSize); + mCorrectedSupportOffset.resize(mSupportSize); + for(unsigned int i=0; im_Coefficients->GetLargestPossibleRegion().GetSize(l); + // DD(a); + // DD(b); + long d2 = 2 * b - 2; + if (a < 0) { + mCorrectedSupportIndex[i][l] = -a - d2*(-a/d2) - EvaluateIndex[l];//mSupportIndex[i][l]-a; + } + else { + if (a>=b) { + mCorrectedSupportIndex[i][l] = d2 - a - EvaluateIndex[l]; + } + else { + mCorrectedSupportIndex[i][l] = mSupportIndex[i][l]; //a - d2*(a/d2) - EvaluateIndex[l]; + } + /* + if (a>=b) { + mCorrectedSupportIndex[i][l] = d2 - a - EvaluateIndex[l];//mSupportIndex[i][l] - (a-(b-1)); + } + else { + mCorrectedSupportIndex[i][l] = mSupportIndex[i][l]; + } + */ + } + } + // DD(mCorrectedSupportIndex[i]); + mCorrectedSupportOffset[i] = Index2Offset(mCorrectedSupportIndex[i], mInputMemoryOffset); + } + // for (unsigned int l=0; lm_Coefficients->GetPixel(EvaluateIndex)); + + // Main loop over BSpline support + TCoefficientType interpolated = 0.0; + for (unsigned int p=0; p +class ITK_EXPORT BSplineResampleImageFunctionWithLUT : + public BSplineInterpolateImageFunctionWithLUT< + TImageType,TCoordRep,ITK_TYPENAME TImageType::PixelType > +{ +public: + /** Standard class typedefs. */ + typedef BSplineResampleImageFunctionWithLUT Self; + typedef BSplineInterpolateImageFunctionWithLUT< + TImageType,TCoordRep, ITK_TYPENAME TImageType::PixelType > Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + /** Run-time type information (and related methods). */ + itkTypeMacro(BSplineReconstructionImageFunction, + BSplineInterpolateImageFunctionWithLUT); + + /** New macro for creation of through a Smart Pointer */ + itkNewMacro( Self ); + + /** Set the input image representing the BSplineCoefficients */ + virtual void SetInputImage(const TImageType * inputData) + { + // bypass my superclass + this->InterpolateImageFunction::SetInputImage(inputData); + this->m_Coefficients = inputData; + if ( this->m_Coefficients.IsNotNull() ) + { + this->m_DataLength = this->m_Coefficients->GetBufferedRegion().GetSize(); + + // JV specific for BLUT ( contains the call to UpdatePrecomputedWeights() ) + this->UpdateWeightsProperties(); + } + } + +protected: + BSplineResampleImageFunctionWithLUT() {}; + virtual ~BSplineResampleImageFunctionWithLUT() {}; + void PrintSelf(std::ostream& os, Indent indent) const + { + this->Superclass::PrintSelf( os, indent ); + } + +private: + BSplineResampleImageFunctionWithLUT(const Self&);//purposely not implemented +}; + +} // namespace itk + + +#endif + diff --git a/itk/itkBSplineWeightsCalculator.h b/itk/itkBSplineWeightsCalculator.h new file mode 100644 index 0000000..18402e8 --- /dev/null +++ b/itk/itkBSplineWeightsCalculator.h @@ -0,0 +1,113 @@ +/* ========================================================================= + + @file itkBSplineWeightsCalculator.h + @author David Sarrut + + Copyright (c) + * CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). + All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + * Léon Bérard cancer center, 28 rue Laënnec, 69373 Lyon cedex 08, France + * http://www.creatis.insa-lyon.fr/rio + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +========================================================================= */ + +#ifndef ITKBSPLINEWEIGHTSCALCULATOR_H +#define ITKBSPLINEWEIGHTSCALCULATOR_H + +#include +#include +#include + +namespace itk { + + //==================================================================== + template + typename Index::IndexValueType Index2Offset(const Index & index, + const Index & offsetTable); + + //==================================================================== + template + class BSplineWeightsCalculator { + + public: + // Some typedef + typedef Index IndexType; + typedef Size SizeType; + typedef ContinuousIndex ContinuousIndexType; + typedef typename IndexType::IndexValueType IndexValueType; + typedef typename SizeType::SizeValueType SizeValueType; + typedef std::vector > InitialWeightsType; + + // Constructor + BSplineWeightsCalculator(); + + // Set order of the spline (could be different in each dimension) + void SetSplineOrder(int splineOrder); + void SetSplineOrders(const SizeType & splineOrder); + + // Set the sampling factor (could be different in each dimension) + void SetSamplingFactor(int sampling); + void SetSamplingFactors(const SizeType & sampling); + + // Main function : compute the tensor product at sampling positions + void ComputeTensorProducts(); + + // Must be used only after ComputeTensorProducts ! + const TCoefficientType * GetFirstTensorProduct(const IndexType & index) const; + + protected: + SizeType mSplineOrders; + SizeType mSplineSupport; + SizeType mSamplingFactors; + + // Number of points in the BSpline support + int mSupportSize; + + // nD Index of all points in the BSpline support + std::vector mSupportIndex; + + // mBasisFunctionCoefficientsMatrix : map of 2D matrix for basic function of arbitrary order + // Could be computed once for all if needed. + // index map = BSpline order + // X = support size + // Y = support size + std::map mBasisFunctionCoefficientsMatrix; + + // mWeights : 3D array with : + // X = dimension number + // Y = support position 1D index + // Z = sampling position 1D index + std::vector > > mWeights; + + // mTensorProducts : 2D array with : + // X = sampling position 1D index + // Y = support position 1D index + std::vector > mTensorProducts; + + + IndexType mTensorProductMemoryOffset; + + bool mWeightsAreUpToDate; + std::map mBasisFunctionCoefficientsMatrixAreUpToDate; + bool mTensorProductsAreUpToDate; + + void ComputeSampledWeights(); + void ComputeSampledWeights1D(std::vector > & w, int order, int sampling); + TCoefficientType BSplineEvaluate(int order, int b, double e); + InitialWeightsType & GetInitialWeights(int order); + void ComputeBasisFunctionCoefficientsMatrix(int order); + double BinomialCoefficient(int i, int j); + + }; // end class itkBSplineWeightsCalculator + +#include "itkBSplineWeightsCalculator.txx" + +} // end namespace + +#endif /* end #define ITKBSPLINEWEIGHTSCALCULATOR_H */ + diff --git a/itk/itkBSplineWeightsCalculator.txx b/itk/itkBSplineWeightsCalculator.txx new file mode 100644 index 0000000..d612768 --- /dev/null +++ b/itk/itkBSplineWeightsCalculator.txx @@ -0,0 +1,273 @@ +/* ========================================================================= + + @file itkBSplineWeightsCalculator.h + @author David Sarrut + + Copyright (c) + * CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). + All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + * Léon Bérard cancer center, 28 rue Laënnec, 69373 Lyon cedex 08, France + * http://www.creatis.insa-lyon.fr/rio + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +========================================================================= */ + +#ifndef ITKBSPLINEWEIGHTSCALCULATOR_TXX +#define ITKBSPLINEWEIGHTSCALCULATOR_TXX + +//==================================================================== +template +typename Index::IndexValueType Index2Offset(const Index & index, const Index & offsetTable) { + long v = index[0]; + for(int l=1; l +BSplineWeightsCalculator:: +BSplineWeightsCalculator() { + mWeightsAreUpToDate = false; +} +//==================================================================== + +//==================================================================== +template +void BSplineWeightsCalculator:: +SetSplineOrder(int splineOrder) { + SizeType temp; + for(int l=0; l +void BSplineWeightsCalculator:: +SetSplineOrders(const SizeType & splineOrder) { + // Compute support size + mSupportSize = 1; + for(int l=0; l +void BSplineWeightsCalculator:: +SetSamplingFactor(int sampling) { + for(int l=0; l +void BSplineWeightsCalculator:: +SetSamplingFactors(const SizeType & sampling) { + for(int l=0; l +typename BSplineWeightsCalculator::InitialWeightsType & +BSplineWeightsCalculator:: +GetInitialWeights(int order) { + if (!mBasisFunctionCoefficientsMatrixAreUpToDate[order]) ComputeBasisFunctionCoefficientsMatrix(order); + return mBasisFunctionCoefficientsMatrix[order]; +} +//==================================================================== + +//==================================================================== +template inline T factorial(T rhs) { + T lhs = (T)1; + for(T x=(T)1; x<=rhs; ++x) { + lhs *= x; + } + return lhs; +} +//==================================================================== + +//==================================================================== +template +double BSplineWeightsCalculator:: +BinomialCoefficient(int i, int j) { + double f = (factorial(i))/(factorial(j) * factorial(i-j)); + return f; +} +//==================================================================== + +//==================================================================== +template +void BSplineWeightsCalculator:: +ComputeBasisFunctionCoefficientsMatrix(int order) { + // Compute the sxs matrix of coefficients used to build the different + // polynomials. With s the support is order+1. + int s = order+1; + mBasisFunctionCoefficientsMatrix[order] = InitialWeightsType(); + mBasisFunctionCoefficientsMatrix[order].resize(s); + for(int i=0; i +TCoefficientType BSplineWeightsCalculator:: +BSplineEvaluate(int order, int k, double e) { + // Evaluate a BSpline + int s=order+1; + TCoefficientType v = 0.0; + for(int p=0; p +void BSplineWeightsCalculator:: +ComputeSampledWeights1D(std::vector > & w, int order, int sampling) { + int s = order+1; + w.resize(s); + for(int k=0; k + +namespace itk +{ + +/** \class BinaryGuerreroFilter + * \brief * + * The images to be added are set using the methods: + * SetInput1( image1 ); + * SetInput2( image2 ); + * + * \warning No numeric overflow checking is performed in this filter. + * + * \ingroup IntensityImageFilters Multithreaded + */ +namespace Functor { + +template< class TInput1, class TInput2=TInput1, class TOutput=TInput1> +class GuerreroFunctor +{ + public: + GuerreroFunctor() : use_correct_formula(false) + {}; + ~GuerreroFunctor() {}; + bool operator!=( const GuerreroFunctor & ) const + { + return false; + } + bool operator==( const GuerreroFunctor & other ) const + { + return !(*this != other); + } + inline TOutput operator() ( const TInput1 & A, const TInput2 & B) const + { + //A is the reference image + TInput2 Bstar = B - 1000.*blood_mass_factor*(1+B/1000.); + TOutput vol_change; + if (use_correct_formula) + vol_change=static_cast( (A-Bstar) / (1000.+Bstar) ); + else //Use the original formula as described in Guerrero's paper + vol_change=static_cast( 1000. * (Bstar-A) / (A*(1000.+Bstar)) ); + + if (std::isnormal(vol_change)) + return vol_change; + else + return 0.; + } + double blood_mass_factor; + bool use_correct_formula; +}; + +} + +//========================================================================== +template +class ITK_EXPORT BinaryGuerreroFilter : + public +BinaryFunctorImageFilter > + + +{ +public: + /** Standard class typedefs. */ + typedef BinaryGuerreroFilter Self; + typedef BinaryFunctorImageFilter > Superclass; + + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Runtime information support. */ + itkTypeMacro(BinaryGuerreroFilter, + BinaryFunctorImageFilter); + void SetBloodCorrectionFactor(double f) + { + this->GetFunctor().blood_mass_factor=f; + } + void SetUseCorrectFormula(bool use_correct_formula) + { + this->GetFunctor().use_correct_formula=use_correct_formula; + } + + +protected: + BinaryGuerreroFilter() {} + virtual ~BinaryGuerreroFilter() {} + +private: + BinaryGuerreroFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + +}; + +} // end namespace itk + + +#endif diff --git a/itk/itkImageToVTKImageFilter.h b/itk/itkImageToVTKImageFilter.h new file mode 100644 index 0000000..ef36774 --- /dev/null +++ b/itk/itkImageToVTKImageFilter.h @@ -0,0 +1,103 @@ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkImageToVTKImageFilter.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:32:01 $ + Version: $Revision: 1.1 $ + + Copyright (c) 2002 Insight Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __itkImageToVTKImageFilter_h +#define __itkImageToVTKImageFilter_h + +#include "itkVTKImageExport.h" +#include "vtkImageImport.h" +#include "vtkImageData.h" + +namespace itk +{ + +/** \class ImageToVTKImageFilter + * \brief Converts an ITK image into a VTK image and plugs a + * itk data pipeline to a VTK datapipeline. + * + * This class puts together an itkVTKImageExporter and a vtkImageImporter. + * It takes care of the details related to the connection of ITK and VTK + * pipelines. The User will perceive this filter as an adaptor to which + * an itk::Image can be plugged as input and a vtkImage is produced as + * output. + * + * \ingroup ImageFilters + */ +template +class ITK_EXPORT ImageToVTKImageFilter : public ProcessObject +{ +public: + /** Standard class typedefs. */ + typedef ImageToVTKImageFilter Self; + typedef ProcessObject Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(ImageToVTKImageFilter, ProcessObject); + + /** Some typedefs. */ + typedef TInputImage InputImageType; + typedef typename InputImageType::ConstPointer InputImagePointer; + typedef VTKImageExport< InputImageType> ExporterFilterType; + typedef typename ExporterFilterType::Pointer ExporterFilterPointer; + + /** Get the output in the form of a vtkImage. + This call is delegated to the internal vtkImageImporter filter */ + vtkImageData * GetOutput() const; + + /** Set the input in the form of an itk::Image */ + void SetInput( const InputImageType * ); + + /** Return the internal VTK image importer filter. + This is intended to facilitate users the access + to methods in the importer */ + vtkImageImport * GetImporter() const; + + /** Return the internal ITK image exporter filter. + This is intended to facilitate users the access + to methods in the exporter */ + ExporterFilterType * GetExporter() const; + + /** This call delegate the update to the importer */ + void Update(); + +protected: + ImageToVTKImageFilter(); + virtual ~ImageToVTKImageFilter(); + +private: + ImageToVTKImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + ExporterFilterPointer m_Exporter; + vtkImageImport * m_Importer; + +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkImageToVTKImageFilter.txx" +#endif + +#endif + + + diff --git a/itk/itkImageToVTKImageFilter.txx b/itk/itkImageToVTKImageFilter.txx new file mode 100644 index 0000000..e50d53b --- /dev/null +++ b/itk/itkImageToVTKImageFilter.txx @@ -0,0 +1,144 @@ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkImageToVTKImageFilter.txx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:32:01 $ + Version: $Revision: 1.1 $ + + Copyright (c) 2002 Insight Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef _itkImageToVTKImageFilter_txx +#define _itkImageToVTKImageFilter_txx + +#include "itkImageToVTKImageFilter.h" + +namespace itk +{ + + + +/** + * Constructor + */ +template +ImageToVTKImageFilter +::ImageToVTKImageFilter() +{ + + m_Importer = vtkImageImport::New(); + + m_Exporter = ExporterFilterType::New(); + + m_Importer->SetUpdateInformationCallback(m_Exporter->GetUpdateInformationCallback()); + m_Importer->SetPipelineModifiedCallback(m_Exporter->GetPipelineModifiedCallback()); + m_Importer->SetWholeExtentCallback(m_Exporter->GetWholeExtentCallback()); + m_Importer->SetSpacingCallback(m_Exporter->GetSpacingCallback()); + m_Importer->SetOriginCallback(m_Exporter->GetOriginCallback()); + m_Importer->SetScalarTypeCallback(m_Exporter->GetScalarTypeCallback()); + m_Importer->SetNumberOfComponentsCallback(m_Exporter->GetNumberOfComponentsCallback()); + m_Importer->SetPropagateUpdateExtentCallback(m_Exporter->GetPropagateUpdateExtentCallback()); + m_Importer->SetUpdateDataCallback(m_Exporter->GetUpdateDataCallback()); + m_Importer->SetDataExtentCallback(m_Exporter->GetDataExtentCallback()); + m_Importer->SetBufferPointerCallback(m_Exporter->GetBufferPointerCallback()); + m_Importer->SetCallbackUserData(m_Exporter->GetCallbackUserData()); + +} + + + + +/** + * Destructor + */ +template +ImageToVTKImageFilter +::~ImageToVTKImageFilter() +{ + if ( m_Importer ) + { + m_Importer->Delete(); + m_Importer = 0; + } +} + + + +/** + * Set an itk::Image as input + */ +template +void +ImageToVTKImageFilter +::SetInput( const InputImageType * inputImage ) +{ + m_Exporter->SetInput( inputImage ); +} + + + +/** + * Get a vtkImage as output + */ +template +vtkImageData * +ImageToVTKImageFilter +::GetOutput() const +{ + return m_Importer->GetOutput(); +} + + + + +/** + * Get the importer filter + */ +template +vtkImageImport * +ImageToVTKImageFilter +::GetImporter() const +{ + return m_Importer; +} + + + +/** + * Get the exporter filter + */ +template +typename ImageToVTKImageFilter::ExporterFilterType * +ImageToVTKImageFilter +::GetExporter() const +{ + return m_Exporter.GetPointer(); +} + + + +/** + * Delegate the Update to the importer + */ +template +void +ImageToVTKImageFilter +::Update() +{ + m_Importer->Update(); +} + + + + + +} // end namespace itk + +#endif + diff --git a/itk/itkRayCastInterpolateImageFunctionWithOrigin.h b/itk/itkRayCastInterpolateImageFunctionWithOrigin.h new file mode 100644 index 0000000..6e8b2ec --- /dev/null +++ b/itk/itkRayCastInterpolateImageFunctionWithOrigin.h @@ -0,0 +1,206 @@ +/*========================================================================= + +Program: Insight Segmentation & Registration Toolkit +Module: $RCSfile: itkRayCastInterpolateImageFunctionWithOrigin.h,v $ +Language: C++ +Date: $Date: 2010/01/06 13:32:01 $ +Version: $Revision: 1.1 $ + +Copyright (c) Insight Software Consortium. All rights reserved. +See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +//JV Support to origin is added, and the implicit shift to the center of the center of the volume removed by two patches + +#ifndef __itkRayCastInterpolateImageFunctionWithOrigin_h +#define __itkRayCastInterpolateImageFunctionWithOrigin_h + +#include "itkInterpolateImageFunction.h" +#include "itkTransform.h" +#include "itkVector.h" + +namespace itk +{ + +/** \class RayCastInterpolateImageFunctionWithOrigin + * \brief Projective interpolation of an image at specified positions. + * + * RayCastInterpolateImageFunctionWithOrigin casts rays through a 3-dimensional + * image and uses bilinear interpolation to integrate each plane of + * voxels traversed. + * + * \warning This interpolator works for 3-dimensional images only. + * + * \ingroup ImageFunctions + */ +template +class ITK_EXPORT RayCastInterpolateImageFunctionWithOrigin : + public InterpolateImageFunction +{ +public: + /** Standard class typedefs. */ + typedef RayCastInterpolateImageFunctionWithOrigin Self; + typedef InterpolateImageFunction Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + /** Constants for the image dimensions */ + itkStaticConstMacro(InputImageDimension, unsigned int, + TInputImage::ImageDimension); + + /** + * Type of the Transform Base class + * The fixed image should be a 3D image + */ + typedef Transform TransformType; + + typedef typename TransformType::Pointer TransformPointer; + typedef typename TransformType::InputPointType InputPointType; + typedef typename TransformType::OutputPointType OutputPointType; + typedef typename TransformType::ParametersType TransformParametersType; + typedef typename TransformType::JacobianType TransformJacobianType; + + typedef typename Superclass::InputPixelType PixelType; + + typedef typename TInputImage::SizeType SizeType; + + typedef Vector DirectionType; + + /** Type of the Interpolator Base class */ + typedef InterpolateImageFunction InterpolatorType; + + typedef typename InterpolatorType::Pointer InterpolatorPointer; + + + /** Run-time type information (and related methods). */ + itkTypeMacro(RayCastInterpolateImageFunctionWithOrigin, InterpolateImageFunction); + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** OutputType typedef support. */ + typedef typename Superclass::OutputType OutputType; + + /** InputImageType typedef support. */ + typedef typename Superclass::InputImageType InputImageType; + + /** RealType typedef support. */ + typedef typename Superclass::RealType RealType; + + /** Dimension underlying input image. */ + itkStaticConstMacro(ImageDimension, unsigned int,Superclass::ImageDimension); + + /** Point typedef support. */ + typedef typename Superclass::PointType PointType; + + /** Index typedef support. */ + typedef typename Superclass::IndexType IndexType; + + /** ContinuousIndex typedef support. */ + typedef typename Superclass::ContinuousIndexType ContinuousIndexType; + + /** \brief + * Interpolate the image at a point position. + * + * Returns the interpolated image intensity at a + * specified point position. No bounds checking is done. + * The point is assume to lie within the image buffer. + * + * ImageFunction::IsInsideBuffer() can be used to check bounds before + * calling the method. + */ + virtual OutputType Evaluate( const PointType& point ) const; + + /** Interpolate the image at a continuous index position + * + * Returns the interpolated image intensity at a + * specified index position. No bounds checking is done. + * The point is assume to lie within the image buffer. + * + * Subclasses must override this method. + * + * ImageFunction::IsInsideBuffer() can be used to check bounds before + * calling the method. + */ + virtual OutputType EvaluateAtContinuousIndex( + const ContinuousIndexType &index ) const; + + + /** Connect the Transform. */ + itkSetObjectMacro( Transform, TransformType ); + /** Get a pointer to the Transform. */ + itkGetObjectMacro( Transform, TransformType ); + + /** Connect the Interpolator. */ + itkSetObjectMacro( Interpolator, InterpolatorType ); + /** Get a pointer to the Interpolator. */ + itkGetObjectMacro( Interpolator, InterpolatorType ); + + /** Connect the Interpolator. */ + itkSetMacro( FocalPoint, InputPointType ); + /** Get a pointer to the Interpolator. */ + itkGetMacro( FocalPoint, InputPointType ); + + /** Connect the Transform. */ + itkSetMacro( Threshold, double ); + /** Get a pointer to the Transform. */ + itkGetMacro( Threshold, double ); + + /** Check if a point is inside the image buffer. + * \warning For efficiency, no validity checking of + * the input image pointer is done. */ + inline bool IsInsideBuffer( const PointType & ) const + { + return true; + } + bool IsInsideBuffer( const ContinuousIndexType & ) const + { + return true; + } + bool IsInsideBuffer( const IndexType & ) const + { + return true; + } + +protected: + + /// Constructor + RayCastInterpolateImageFunctionWithOrigin(); + + /// Destructor + ~RayCastInterpolateImageFunctionWithOrigin(){}; + + /// Print the object + void PrintSelf(std::ostream& os, Indent indent) const; + + /// Transformation used to calculate the new focal point position + TransformPointer m_Transform; + + /// The focal point or position of the ray source + InputPointType m_FocalPoint; + + /// The threshold above which voxels along the ray path are integrated. + double m_Threshold; + + /// Pointer to the interpolator + InterpolatorPointer m_Interpolator; + + +private: + RayCastInterpolateImageFunctionWithOrigin( const Self& ); //purposely not implemented + void operator=( const Self& ); //purposely not implemented + + +}; + +} // namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkRayCastInterpolateImageFunctionWithOrigin.txx" +#endif + +#endif diff --git a/itk/itkRayCastInterpolateImageFunctionWithOrigin.txx b/itk/itkRayCastInterpolateImageFunctionWithOrigin.txx new file mode 100644 index 0000000..d6504a4 --- /dev/null +++ b/itk/itkRayCastInterpolateImageFunctionWithOrigin.txx @@ -0,0 +1,1569 @@ +/*========================================================================= + +Program: Insight Segmentation & Registration Toolkit +Module: $RCSfile: itkRayCastInterpolateImageFunctionWithOrigin.txx,v $ +Language: C++ +Date: $Date: 2010/01/06 13:32:01 $ +Version: $Revision: 1.1 $ + +Copyright (c) Insight Software Consortium. All rights reserved. +See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __itkRayCastInterpolateImageFunctionWithOrigin_txx +#define __itkRayCastInterpolateImageFunctionWithOrigin_txx + +#include "itkRayCastInterpolateImageFunctionWithOrigin.h" + +#include "vnl/vnl_math.h" + + +// Put the helper class in an anonymous namespace so that it is not +// exposed to the user +namespace { + +/** \class Helper class to maintain state when casting a ray. + * This helper class keeps the RayCastInterpolateImageFunctionWithOrigin thread safe. + */ +template +class RayCastHelper +{ +public: + /** Constants for the image dimensions */ + itkStaticConstMacro(InputImageDimension, unsigned int, + TInputImage::ImageDimension); + + /** + * Type of the Transform Base class + * The fixed image should be a 3D image + */ + typedef itk::Transform TransformType; + + typedef typename TransformType::Pointer TransformPointer; + typedef typename TransformType::InputPointType InputPointType; + typedef typename TransformType::OutputPointType OutputPointType; + typedef typename TransformType::ParametersType TransformParametersType; + typedef typename TransformType::JacobianType TransformJacobianType; + + typedef typename TInputImage::SizeType SizeType; + typedef itk::Vector DirectionType; + typedef itk::Point PointType; + + typedef TInputImage InputImageType; + typedef typename InputImageType::PixelType PixelType; + typedef typename InputImageType::IndexType IndexType; + + /** + * Set the image class + */ + void SetImage(const InputImageType *input) + { + m_Image = input; + } + + /** + * Initialise the ray using the position and direction of a line. + * + * \param RayPosn The position of the ray in 3D (mm). + * \param RayDirn The direction of the ray in 3D (mm). + * + * \return True if this is a valid ray. + */ + bool SetRay(OutputPointType RayPosn, DirectionType RayDirn); + + + /** \brief + * Integrate the interpolated intensities along the ray and + * return the result. + * + * This routine can be called after instantiating the ray and + * calling SetProjectionCoord2D() or Reset(). It may then be called + * as many times thereafter for different 2D projection + * coordinates. + * + * \param integral The integrated intensities along the ray. + * + * \return True if a valid ray was specified. + */ + bool Integrate(double &integral) + { + return IntegrateAboveThreshold(integral, 0); + }; + + + /** \brief + * Integrate the interpolated intensities above a given threshold, + * along the ray and return the result. + * + * This routine can be called after instantiating the ray and + * calling SetProjectionCoord2D() or Reset(). It may then be called + * as many times thereafter for different 2D projection + * coordinates. + * + * \param integral The integrated intensities along the ray. + * \param threshold The integration threshold [default value: 0] + * + * \return True if a valid ray was specified. + */ + bool IntegrateAboveThreshold(double &integral, double threshold); + + /** \brief + * Increment each of the intensities of the 4 planar voxels + * surrounding the current ray point. + * + * \parameter increment Intensity increment for each of the current 4 voxels + */ + void IncrementIntensities(double increment=1); + + /// Reset the iterator to the start of the ray. + void Reset(void); + + /// Return the interpolated intensity of the current ray point. + double GetCurrentIntensity(void) const; + + /// Return the ray point spacing in mm + double GetRayPointSpacing(void) const { + typename InputImageType::SpacingType spacing=this->m_Image->GetSpacing(); + + if (m_ValidRay) + return vcl_sqrt(m_VoxelIncrement[0]*spacing[0]*m_VoxelIncrement[0]*spacing[0] + + m_VoxelIncrement[1]*spacing[1]*m_VoxelIncrement[1]*spacing[1] + + m_VoxelIncrement[2]*spacing[2]*m_VoxelIncrement[2]*spacing[2] ); + else + return 0.; + }; + + /// Set the initial zero state of the object + void ZeroState(); + + /// Initialise the object + void Initialise(void); + +protected: + /// Calculate the endpoint coordinats of the ray in voxels. + void EndPointsInVoxels(void); + + /** + * Calculate the incremental direction vector in voxels, 'dVoxel', + * required to traverse the ray. + */ + void CalcDirnVector(void); + + /** + * Reduce the length of the ray until both start and end + * coordinates lie inside the volume. + * + * \return True if a valid ray has been, false otherwise. + */ + bool AdjustRayLength(void); + + /** + * Obtain pointers to the four voxels surrounding the point where the ray + * enters the volume. + */ + void InitialiseVoxelPointers(void); + + /// Increment the voxel pointers surrounding the current point on the ray. + void IncrementVoxelPointers(void); + + /// Record volume dimensions and resolution + void RecordVolumeDimensions(void); + + /// Define the corners of the volume + void DefineCorners(void); + + /** \brief + * Calculate the planes which define the volume. + * + * Member function to calculate the equations of the planes of 4 of + * the sides of the volume, calculate the positions of the 8 corners + * of the volume in mm in World, also calculate the values of the + * slopes of the lines which go to make up the volume( defined as + * lines in cube x,y,z dirn and then each of these lines has a slope + * in the world x,y,z dirn [3]) and finally also to return the length + * of the sides of the lines in mm. + */ + void CalcPlanesAndCorners(void); + + /** \brief + * Calculate the ray intercepts with the volume. + * + * See where the ray cuts the volume, check that truncation does not occur, + * if not, then start ray where it first intercepts the volume and set + * x_max to be where it leaves the volume. + * + * \return True if a valid ray has been specified, false otherwise. + */ + bool CalcRayIntercepts(void); + + /** + * The ray is traversed by stepping in the axial direction + * that enables the greatest number of planes in the volume to be + * intercepted. + */ + typedef enum { + UNDEFINED_DIRECTION=0, //!< Undefined + TRANSVERSE_IN_X, //!< x + TRANSVERSE_IN_Y, //!< y + TRANSVERSE_IN_Z, //!< z + LAST_DIRECTION + } TraversalDirection; + + // Cache the image in the structure. Skip the smart pointer for + // efficiency. This inner class will go in/out of scope with every + // call to Evaluate() + const InputImageType *m_Image; + + /// Flag indicating whether the current ray is valid + bool m_ValidRay; + + /** \brief + * The start position of the ray in voxels. + * + * NB. Two of the components of this coordinate (i.e. those lying within + * the planes of voxels being traversed) will be shifted by half a + * voxel. This enables indices of the neighbouring voxels within the plane + * to be determined by simply casting to 'int' and optionally adding 1. + */ + double m_RayVoxelStartPosition[3]; + + /** \brief + * The end coordinate of the ray in voxels. + * + * NB. Two of the components of this coordinate (i.e. those lying within + * the planes of voxels being traversed) will be shifted by half a + * voxel. This enables indices of the neighbouring voxels within the plane + * to be determined by simply casting to 'int' and optionally adding 1. + */ + double m_RayVoxelEndPosition[3]; + + + /** \brief + * The current coordinate on the ray in voxels. + * + * NB. Two of the components of this coordinate (i.e. those lying within + * the planes of voxels being traversed) will be shifted by half a + * voxel. This enables indices of the neighbouring voxels within the plane + * to be determined by simply casting to 'int' and optionally adding 1. + */ + double m_Position3Dvox[3]; + + /** The incremental direction vector of the ray in voxels. */ + double m_VoxelIncrement[3]; + + /// The direction in which the ray is incremented thorough the volume (x, y or z). + TraversalDirection m_TraversalDirection; + + /// The total number of planes of voxels traversed by the ray. + int m_TotalRayVoxelPlanes; + + /// The current number of planes of voxels traversed by the ray. + int m_NumVoxelPlanesTraversed; + + /// Pointers to the current four voxels surrounding the ray's trajectory. + const PixelType *m_RayIntersectionVoxels[4]; + + /** + * The voxel coordinate of the bottom-left voxel of the current + * four voxels surrounding the ray's trajectory. + */ + int m_RayIntersectionVoxelIndex[3]; + + /// The dimension in voxels of the 3D volume in along the x axis + int m_NumberOfVoxelsInX; + /// The dimension in voxels of the 3D volume in along the y axis + int m_NumberOfVoxelsInY; + /// The dimension in voxels of the 3D volume in along the z axis + int m_NumberOfVoxelsInZ; + + /// Voxel dimension in x + double m_VoxelDimensionInX; + /// Voxel dimension in y + double m_VoxelDimensionInY; + /// Voxel dimension in z + double m_VoxelDimensionInZ; + + /// The coordinate of the point at which the ray enters the volume in mm. + double m_RayStartCoordInMM[3]; + /// The coordinate of the point at which the ray exits the volume in mm. + double m_RayEndCoordInMM[3]; + + + /** \brief + Planes which define the boundary of the volume in mm + (six planes and four parameters: Ax+By+Cz+D). */ + double m_BoundingPlane[6][4]; + /// The eight corners of the volume (x,y,z coordinates for each). + double m_BoundingCorner[8][3]; + + /// The position of the ray + double m_CurrentRayPositionInMM[3]; + + /// The direction of the ray + double m_RayDirectionInMM[3]; + +}; + +/* ----------------------------------------------------------------------- + Initialise() - Initialise the object + ----------------------------------------------------------------------- */ + +template +void +RayCastHelper +::Initialise(void) +{ + // Save the dimensions of the volume and calculate the bounding box + this->RecordVolumeDimensions(); + + // Calculate the planes and corners which define the volume. + this->DefineCorners(); + this->CalcPlanesAndCorners(); +} + + +/* ----------------------------------------------------------------------- + RecordVolumeDimensions() - Record volume dimensions and resolution + ----------------------------------------------------------------------- */ + +template +void +RayCastHelper +::RecordVolumeDimensions(void) +{ + typename InputImageType::SpacingType spacing=this->m_Image->GetSpacing(); + SizeType dim=this->m_Image->GetLargestPossibleRegion().GetSize(); + + m_NumberOfVoxelsInX = dim[0]; + m_NumberOfVoxelsInY = dim[1]; + m_NumberOfVoxelsInZ = dim[2]; + + m_VoxelDimensionInX = spacing[0]; + m_VoxelDimensionInY = spacing[1]; + m_VoxelDimensionInZ = spacing[2]; +} + + +/* ----------------------------------------------------------------------- + DefineCorners() - Define the corners of the volume + ----------------------------------------------------------------------- */ + +template +void +RayCastHelper +::DefineCorners(void) +{ + // Define corner positions as if at the origin + + m_BoundingCorner[0][0] = + m_BoundingCorner[1][0] = + m_BoundingCorner[2][0] = + m_BoundingCorner[3][0] = 0; + + m_BoundingCorner[4][0] = + m_BoundingCorner[5][0] = + m_BoundingCorner[6][0] = + m_BoundingCorner[7][0] = m_VoxelDimensionInX*m_NumberOfVoxelsInX; + + m_BoundingCorner[1][1] = + m_BoundingCorner[3][1] = + m_BoundingCorner[5][1] = + m_BoundingCorner[7][1] = m_VoxelDimensionInY*m_NumberOfVoxelsInY; + + m_BoundingCorner[0][1] = + m_BoundingCorner[2][1] = + m_BoundingCorner[4][1] = + m_BoundingCorner[6][1] = 0; + + m_BoundingCorner[0][2] = + m_BoundingCorner[1][2] = + m_BoundingCorner[4][2] = + m_BoundingCorner[5][2] = + m_VoxelDimensionInZ*m_NumberOfVoxelsInZ; + + m_BoundingCorner[2][2] = + m_BoundingCorner[3][2] = + m_BoundingCorner[6][2] = + m_BoundingCorner[7][2] = 0; + +} + +/* ----------------------------------------------------------------------- + CalcPlanesAndCorners() - Calculate the planes and corners of the volume. + ----------------------------------------------------------------------- */ + +template +void +RayCastHelper +::CalcPlanesAndCorners(void) +{ + int j; + + + // find the equations of the planes + + int c1=0, c2=0, c3=0; + + for (j=0; j<6; j++) + { // loop around for planes + switch (j) + { // which corners to take + case 0: + c1=1; c2=2; c3=3; + break; + case 1: + c1=4; c2=5; c3=6; + break; + case 2: + c1=5; c2=3; c3=7; + break; + case 3: + c1=2; c2=4; c3=6; + break; + case 4: + c1=1; c2=5; c3=0; + break; + case 5: + c1=3; c2=7; c3=2; + break; + } + + + double line1x, line1y, line1z; + double line2x, line2y, line2z; + + // lines from one corner to another in x,y,z dirns + line1x = m_BoundingCorner[c1][0] - m_BoundingCorner[c2][0]; + line2x = m_BoundingCorner[c1][0] - m_BoundingCorner[c3][0]; + + line1y = m_BoundingCorner[c1][1] - m_BoundingCorner[c2][1]; + line2y = m_BoundingCorner[c1][1] - m_BoundingCorner[c3][1]; + + line1z = m_BoundingCorner[c1][2] - m_BoundingCorner[c2][2]; + line2z = m_BoundingCorner[c1][2] - m_BoundingCorner[c3][2]; + + double A, B, C, D; + + // take cross product + A = line1y*line2z - line2y*line1z; + B = line2x*line1z - line1x*line2z; + C = line1x*line2y - line2x*line1y; + + // find constant + D = -( A*m_BoundingCorner[c1][0] + + B*m_BoundingCorner[c1][1] + + C*m_BoundingCorner[c1][2] ); + + // initialise plane value and normalise + m_BoundingPlane[j][0] = A/vcl_sqrt(A*A + B*B + C*C); + m_BoundingPlane[j][1] = B/vcl_sqrt(A*A + B*B + C*C); + m_BoundingPlane[j][2] = C/vcl_sqrt(A*A + B*B + C*C); + m_BoundingPlane[j][3] = D/vcl_sqrt(A*A + B*B + C*C); + + if ( (A*A + B*B + C*C) == 0 ) + { + itk::ExceptionObject err(__FILE__, __LINE__); + err.SetLocation( ITK_LOCATION ); + err.SetDescription( "Division by zero (planes) " + "- CalcPlanesAndCorners()."); + throw err; + } + } + +} + + +/* ----------------------------------------------------------------------- + CalcRayIntercepts() - Calculate the ray intercepts with the volume. + ----------------------------------------------------------------------- */ + +template +bool +RayCastHelper +::CalcRayIntercepts() +{ + double maxInterDist, interDist; + double cornerVect[4][3]; + int cross[4][3], noInterFlag[6]; + int nSidesCrossed, crossFlag, c[4]; + double ax, ay, az, bx, by, bz; + double cubeInter[6][3]; + double denom; + + int i,j, k; + int NoSides = 6; // =6 to allow truncation: =4 to remove truncated rays + + // Calculate intercept of ray with planes + + double interceptx[6], intercepty[6], interceptz[6]; + double d[6]; + + for( j=0; j=0 + && cross[1][i]>=0 + && cross[2][i]>=0 + && cross[3][i]>=0) ) + { + crossFlag++; + } + } + + + if( crossFlag==3 && noInterFlag[j]==1 ) + { + cubeInter[nSidesCrossed][0] = interceptx[j]; + cubeInter[nSidesCrossed][1] = intercepty[j]; + cubeInter[nSidesCrossed][2] = interceptz[j]; + nSidesCrossed++; + } + + } // End of loop over all four planes + + m_RayStartCoordInMM[0] = cubeInter[0][0]; + m_RayStartCoordInMM[1] = cubeInter[0][1]; + m_RayStartCoordInMM[2] = cubeInter[0][2]; + + m_RayEndCoordInMM[0] = cubeInter[1][0]; + m_RayEndCoordInMM[1] = cubeInter[1][1]; + m_RayEndCoordInMM[2] = cubeInter[1][2]; + + if( nSidesCrossed >= 5 ) + { + std::cerr << "WARNING: No. of sides crossed equals: " << nSidesCrossed << std::endl; + } + + // If 'nSidesCrossed' is larger than 2, this means that the ray goes through + // a corner of the volume and due to rounding errors, the ray is + // deemed to go through more than two planes. To obtain the correct + // start and end positions we choose the two intercept values which + // are furthest from each other. + + + if( nSidesCrossed >= 3 ) + { + maxInterDist = 0; + for( j=0; j maxInterDist ) + { + maxInterDist = interDist; + + m_RayStartCoordInMM[0] = cubeInter[j][0]; + m_RayStartCoordInMM[1] = cubeInter[j][1]; + m_RayStartCoordInMM[2] = cubeInter[j][2]; + + m_RayEndCoordInMM[0] = cubeInter[k][0]; + m_RayEndCoordInMM[1] = cubeInter[k][1]; + m_RayEndCoordInMM[2] = cubeInter[k][2]; + } + } + } + nSidesCrossed = 2; + } + + if (nSidesCrossed == 2 ) + { + return true; + } + else + { + return false; + } +} + + +/* ----------------------------------------------------------------------- + SetRay() - Set the position and direction of the ray + ----------------------------------------------------------------------- */ + +template +bool +RayCastHelper +::SetRay(OutputPointType RayPosn, DirectionType RayDirn) +{ + + // Store the position and direction of the ray + typename TInputImage::SpacingType spacing=this->m_Image->GetSpacing(); + SizeType dim=this->m_Image->GetLargestPossibleRegion().GetSize(); + + // we need to translate the _center_ of the volume to the origin + m_NumberOfVoxelsInX = dim[0]; + m_NumberOfVoxelsInY = dim[1]; + m_NumberOfVoxelsInZ = dim[2]; + + m_VoxelDimensionInX = spacing[0]; + m_VoxelDimensionInY = spacing[1]; + m_VoxelDimensionInZ = spacing[2]; + + // (Aviv) Incorporating a fix by Jian Wu + // http://public.kitware.com/pipermail/insight-users/2006-March/017265.html + m_CurrentRayPositionInMM[0] = RayPosn[0]; + m_CurrentRayPositionInMM[1] = RayPosn[1]; + m_CurrentRayPositionInMM[2] = RayPosn[2]; + + m_RayDirectionInMM[0] = RayDirn[0]; + m_RayDirectionInMM[1] = RayDirn[1]; + m_RayDirectionInMM[2] = RayDirn[2]; + + // Compute the ray path for this coordinate in mm + + m_ValidRay = this->CalcRayIntercepts(); + + if (! m_ValidRay) + { + Reset(); + return false; + } + + // Convert the start and end coordinates of the ray to voxels + + this->EndPointsInVoxels(); + + /* Calculate the ray direction vector in voxels and hence the voxel + increment required to traverse the ray, and the number of + interpolation points on the ray. + + This routine also shifts the coordinate frame by half a voxel for + two of the directional components (i.e. those lying within the + planes of voxels being traversed). */ + + this->CalcDirnVector(); + + + /* Reduce the length of the ray until both start and end + coordinates lie inside the volume. */ + + m_ValidRay = this->AdjustRayLength(); + + // Reset the iterator to the start of the ray. + + Reset(); + + return m_ValidRay; +} + + +/* ----------------------------------------------------------------------- + EndPointsInVoxels() - Convert the endpoints to voxels + ----------------------------------------------------------------------- */ + +template +void +RayCastHelper +::EndPointsInVoxels(void) +{ + m_RayVoxelStartPosition[0] = m_RayStartCoordInMM[0]/m_VoxelDimensionInX; + m_RayVoxelStartPosition[1] = m_RayStartCoordInMM[1]/m_VoxelDimensionInY; + m_RayVoxelStartPosition[2] = m_RayStartCoordInMM[2]/m_VoxelDimensionInZ; + + m_RayVoxelEndPosition[0] = m_RayEndCoordInMM[0]/m_VoxelDimensionInX; + m_RayVoxelEndPosition[1] = m_RayEndCoordInMM[1]/m_VoxelDimensionInY; + m_RayVoxelEndPosition[2] = m_RayEndCoordInMM[2]/m_VoxelDimensionInZ; + +} + + +/* ----------------------------------------------------------------------- + CalcDirnVector() - Calculate the incremental direction vector in voxels. + ----------------------------------------------------------------------- */ + +template +void +RayCastHelper +::CalcDirnVector(void) +{ + double xNum, yNum, zNum; + + // Calculate the number of voxels in each direction + + xNum = vcl_fabs(m_RayVoxelStartPosition[0] - m_RayVoxelEndPosition[0]); + yNum = vcl_fabs(m_RayVoxelStartPosition[1] - m_RayVoxelEndPosition[1]); + zNum = vcl_fabs(m_RayVoxelStartPosition[2] - m_RayVoxelEndPosition[2]); + + // The direction iterated in is that with the greatest number of voxels + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + // Iterate in X direction + + if( (xNum >= yNum) && (xNum >= zNum) ) + { + if( m_RayVoxelStartPosition[0] < m_RayVoxelEndPosition[0] ) + { + m_VoxelIncrement[0] = 1; + + m_VoxelIncrement[1] + = (m_RayVoxelStartPosition[1] + - m_RayVoxelEndPosition[1])/(m_RayVoxelStartPosition[0] + - m_RayVoxelEndPosition[0]); + + m_VoxelIncrement[2] + = (m_RayVoxelStartPosition[2] + - m_RayVoxelEndPosition[2])/(m_RayVoxelStartPosition[0] + - m_RayVoxelEndPosition[0]); + } + else + { + m_VoxelIncrement[0] = -1; + + m_VoxelIncrement[1] + = -(m_RayVoxelStartPosition[1] + - m_RayVoxelEndPosition[1])/(m_RayVoxelStartPosition[0] + - m_RayVoxelEndPosition[0]); + + m_VoxelIncrement[2] + = -(m_RayVoxelStartPosition[2] + - m_RayVoxelEndPosition[2])/(m_RayVoxelStartPosition[0] + - m_RayVoxelEndPosition[0]); + } + + // This section is to alter the start position in order to + // place the center of the voxels in there correct positions, + // rather than placing them at the corner of voxels which is + // what happens if this is not carried out. The reason why + // x has no -0.5 is because this is the direction we are going + // to iterate in and therefore we wish to go from center to + // center rather than finding the surrounding voxels. + + m_RayVoxelStartPosition[1] += ( (int)m_RayVoxelStartPosition[0] + - m_RayVoxelStartPosition[0])*m_VoxelIncrement[1]*m_VoxelIncrement[0] + + 0.5*m_VoxelIncrement[1] - 0.5; + + m_RayVoxelStartPosition[2] += ( (int)m_RayVoxelStartPosition[0] + - m_RayVoxelStartPosition[0])*m_VoxelIncrement[2]*m_VoxelIncrement[0] + + 0.5*m_VoxelIncrement[2] - 0.5; + + m_RayVoxelStartPosition[0] = (int)m_RayVoxelStartPosition[0] + 0.5*m_VoxelIncrement[0]; + + m_TotalRayVoxelPlanes = (int)xNum; + + m_TraversalDirection = TRANSVERSE_IN_X; + } + + // Iterate in Y direction + + else if( (yNum >= xNum) && (yNum >= zNum) ) + { + + if( m_RayVoxelStartPosition[1] < m_RayVoxelEndPosition[1] ) + { + m_VoxelIncrement[1] = 1; + + m_VoxelIncrement[0] + = (m_RayVoxelStartPosition[0] + - m_RayVoxelEndPosition[0])/(m_RayVoxelStartPosition[1] + - m_RayVoxelEndPosition[1]); + + m_VoxelIncrement[2] + = (m_RayVoxelStartPosition[2] + - m_RayVoxelEndPosition[2])/(m_RayVoxelStartPosition[1] + - m_RayVoxelEndPosition[1]); + } + else + { + m_VoxelIncrement[1] = -1; + + m_VoxelIncrement[0] + = -(m_RayVoxelStartPosition[0] + - m_RayVoxelEndPosition[0])/(m_RayVoxelStartPosition[1] + - m_RayVoxelEndPosition[1]); + + m_VoxelIncrement[2] + = -(m_RayVoxelStartPosition[2] + - m_RayVoxelEndPosition[2])/(m_RayVoxelStartPosition[1] + - m_RayVoxelEndPosition[1]); + } + + m_RayVoxelStartPosition[0] += ( (int)m_RayVoxelStartPosition[1] + - m_RayVoxelStartPosition[1])*m_VoxelIncrement[0]*m_VoxelIncrement[1] + + 0.5*m_VoxelIncrement[0] - 0.5; + + m_RayVoxelStartPosition[2] += ( (int)m_RayVoxelStartPosition[1] + - m_RayVoxelStartPosition[1])*m_VoxelIncrement[2]*m_VoxelIncrement[1] + + 0.5*m_VoxelIncrement[2] - 0.5; + + m_RayVoxelStartPosition[1] = (int)m_RayVoxelStartPosition[1] + 0.5*m_VoxelIncrement[1]; + + m_TotalRayVoxelPlanes = (int)yNum; + + m_TraversalDirection = TRANSVERSE_IN_Y; + } + + // Iterate in Z direction + + else + { + + if( m_RayVoxelStartPosition[2] < m_RayVoxelEndPosition[2] ) + { + m_VoxelIncrement[2] = 1; + + m_VoxelIncrement[0] + = (m_RayVoxelStartPosition[0] + - m_RayVoxelEndPosition[0])/(m_RayVoxelStartPosition[2] + - m_RayVoxelEndPosition[2]); + + m_VoxelIncrement[1] + = (m_RayVoxelStartPosition[1] + - m_RayVoxelEndPosition[1])/(m_RayVoxelStartPosition[2] + - m_RayVoxelEndPosition[2]); + } + else + { + m_VoxelIncrement[2] = -1; + + m_VoxelIncrement[0] + = -(m_RayVoxelStartPosition[0] + - m_RayVoxelEndPosition[0])/(m_RayVoxelStartPosition[2] + - m_RayVoxelEndPosition[2]); + + m_VoxelIncrement[1] + = -(m_RayVoxelStartPosition[1] + - m_RayVoxelEndPosition[1])/(m_RayVoxelStartPosition[2] + - m_RayVoxelEndPosition[2]); + } + + m_RayVoxelStartPosition[0] += ( (int)m_RayVoxelStartPosition[2] + - m_RayVoxelStartPosition[2])*m_VoxelIncrement[0]*m_VoxelIncrement[2] + + 0.5*m_VoxelIncrement[0] - 0.5; + + m_RayVoxelStartPosition[1] += ( (int)m_RayVoxelStartPosition[2] + - m_RayVoxelStartPosition[2])*m_VoxelIncrement[1]*m_VoxelIncrement[2] + + 0.5*m_VoxelIncrement[1] - 0.5; + + m_RayVoxelStartPosition[2] = (int)m_RayVoxelStartPosition[2] + 0.5*m_VoxelIncrement[2]; + + m_TotalRayVoxelPlanes = (int)zNum; + + m_TraversalDirection = TRANSVERSE_IN_Z; + } +} + + +/* ----------------------------------------------------------------------- + AdjustRayLength() - Ensure that the ray lies within the volume + ----------------------------------------------------------------------- */ + +template +bool +RayCastHelper +::AdjustRayLength(void) +{ + bool startOK, endOK; + + int Istart[3]; + int Idirn[3]; + + if (m_TraversalDirection == TRANSVERSE_IN_X) + { + Idirn[0] = 0; + Idirn[1] = 1; + Idirn[2] = 1; + } + else if (m_TraversalDirection == TRANSVERSE_IN_Y) + { + Idirn[0] = 1; + Idirn[1] = 0; + Idirn[2] = 1; + } + else if (m_TraversalDirection == TRANSVERSE_IN_Z) + { + Idirn[0] = 1; + Idirn[1] = 1; + Idirn[2] = 0; + } + else + { + itk::ExceptionObject err(__FILE__, __LINE__); + err.SetLocation( ITK_LOCATION ); + err.SetDescription( "The ray traversal direction is unset " + "- AdjustRayLength()."); + throw err; + return false; + } + + + do + { + + startOK = false; + endOK = false; + + Istart[0] = (int) vcl_floor(m_RayVoxelStartPosition[0]); + Istart[1] = (int) vcl_floor(m_RayVoxelStartPosition[1]); + Istart[2] = (int) vcl_floor(m_RayVoxelStartPosition[2]); + + if( (Istart[0] >= 0) && (Istart[0] + Idirn[0] < m_NumberOfVoxelsInX) && + (Istart[1] >= 0) && (Istart[1] + Idirn[1] < m_NumberOfVoxelsInY) && + (Istart[2] >= 0) && (Istart[2] + Idirn[2] < m_NumberOfVoxelsInZ) ) + { + + startOK = true; + } + else + { + m_RayVoxelStartPosition[0] += m_VoxelIncrement[0]; + m_RayVoxelStartPosition[1] += m_VoxelIncrement[1]; + m_RayVoxelStartPosition[2] += m_VoxelIncrement[2]; + + m_TotalRayVoxelPlanes--; + } + + Istart[0] = (int) vcl_floor(m_RayVoxelStartPosition[0] + + m_TotalRayVoxelPlanes*m_VoxelIncrement[0]); + + Istart[1] = (int) vcl_floor(m_RayVoxelStartPosition[1] + + m_TotalRayVoxelPlanes*m_VoxelIncrement[1]); + + Istart[2] = (int) vcl_floor(m_RayVoxelStartPosition[2] + + m_TotalRayVoxelPlanes*m_VoxelIncrement[2]); + + if( (Istart[0] >= 0) && (Istart[0] + Idirn[0] < m_NumberOfVoxelsInX) && + (Istart[1] >= 0) && (Istart[1] + Idirn[1] < m_NumberOfVoxelsInY) && + (Istart[2] >= 0) && (Istart[2] + Idirn[2] < m_NumberOfVoxelsInZ) ) + { + + endOK = true; + } + else + { + m_TotalRayVoxelPlanes--; + } + + } while ( (! (startOK && endOK)) && (m_TotalRayVoxelPlanes > 1) ); + + + return (startOK && endOK); +} + + +/* ----------------------------------------------------------------------- + Reset() - Reset the iterator to the start of the ray. + ----------------------------------------------------------------------- */ + +template +void +RayCastHelper +::Reset(void) +{ + int i; + + m_NumVoxelPlanesTraversed = -1; + + // If this is a valid ray... + + if (m_ValidRay) + { + for (i=0; i<3; i++) + { + m_Position3Dvox[i] = m_RayVoxelStartPosition[i]; + } + this->InitialiseVoxelPointers(); + } + + // otherwise set parameters to zero + + else + { + for (i=0; i<3; i++) + { + m_RayVoxelStartPosition[i] = 0.; + } + for (i=0; i<3; i++) + { + m_RayVoxelEndPosition[i] = 0.; + } + for (i=0; i<3; i++) + { + m_VoxelIncrement[i] = 0.; + } + m_TraversalDirection = UNDEFINED_DIRECTION; + + m_TotalRayVoxelPlanes = 0; + + for (i=0; i<4; i++) + { + m_RayIntersectionVoxels[i] = 0; + } + for (i=0; i<3; i++) + { + m_RayIntersectionVoxelIndex[i] = 0; + } + } +} + + +/* ----------------------------------------------------------------------- + InitialiseVoxelPointers() - Obtain pointers to the first four voxels + ----------------------------------------------------------------------- */ + +template +void +RayCastHelper +::InitialiseVoxelPointers(void) +{ + IndexType index; + + int Ix, Iy, Iz; + + Ix = (int)(m_RayVoxelStartPosition[0]); + Iy = (int)(m_RayVoxelStartPosition[1]); + Iz = (int)(m_RayVoxelStartPosition[2]); + + m_RayIntersectionVoxelIndex[0] = Ix; + m_RayIntersectionVoxelIndex[1] = Iy; + m_RayIntersectionVoxelIndex[2] = Iz; + + switch( m_TraversalDirection ) + { + case TRANSVERSE_IN_X: + { + + if( (Ix >= 0) && (Ix < m_NumberOfVoxelsInX) && + (Iy >= 0) && (Iy + 1 < m_NumberOfVoxelsInY) && + (Iz >= 0) && (Iz + 1 < m_NumberOfVoxelsInZ)) + { + + index[0]=Ix; index[1]=Iy; index[2]=Iz; + m_RayIntersectionVoxels[0] + = this->m_Image->GetBufferPointer() + this->m_Image->ComputeOffset(index); + + index[0]=Ix; index[1]=Iy+1; index[2]=Iz; + m_RayIntersectionVoxels[1] + = ( this->m_Image->GetBufferPointer() + this->m_Image->ComputeOffset(index) ); + + index[0]=Ix; index[1]=Iy; index[2]=Iz+1; + m_RayIntersectionVoxels[2] + = ( this->m_Image->GetBufferPointer() + this->m_Image->ComputeOffset(index) ); + + index[0]=Ix; index[1]=Iy+1; index[2]=Iz+1; + m_RayIntersectionVoxels[3] + = ( this->m_Image->GetBufferPointer() + this->m_Image->ComputeOffset(index) ); + } + else + { + m_RayIntersectionVoxels[0] = + m_RayIntersectionVoxels[1] = + m_RayIntersectionVoxels[2] = + m_RayIntersectionVoxels[3] = NULL; + } + break; + } + + case TRANSVERSE_IN_Y: + { + + if( (Ix >= 0) && (Ix + 1 < m_NumberOfVoxelsInX) && + (Iy >= 0) && (Iy < m_NumberOfVoxelsInY) && + (Iz >= 0) && (Iz + 1 < m_NumberOfVoxelsInZ)) + { + + index[0]=Ix; index[1]=Iy; index[2]=Iz; + m_RayIntersectionVoxels[0] = ( this->m_Image->GetBufferPointer() + + this->m_Image->ComputeOffset(index) ); + + index[0]=Ix+1; index[1]=Iy; index[2]=Iz; + m_RayIntersectionVoxels[1] = ( this->m_Image->GetBufferPointer() + + this->m_Image->ComputeOffset(index) ); + + index[0]=Ix; index[1]=Iy; index[2]=Iz+1; + m_RayIntersectionVoxels[2] = ( this->m_Image->GetBufferPointer() + + this->m_Image->ComputeOffset(index) ); + + index[0]=Ix+1; index[1]=Iy; index[2]=Iz+1; + m_RayIntersectionVoxels[3] = ( this->m_Image->GetBufferPointer() + + this->m_Image->ComputeOffset(index) ); + } + else + { + m_RayIntersectionVoxels[0] + = m_RayIntersectionVoxels[1] + = m_RayIntersectionVoxels[2] + = m_RayIntersectionVoxels[3] = NULL; + } + break; + } + + case TRANSVERSE_IN_Z: + { + + if( (Ix >= 0) && (Ix + 1 < m_NumberOfVoxelsInX) && + (Iy >= 0) && (Iy + 1 < m_NumberOfVoxelsInY) && + (Iz >= 0) && (Iz < m_NumberOfVoxelsInZ)) + { + + index[0]=Ix; index[1]=Iy; index[2]=Iz; + m_RayIntersectionVoxels[0] = ( this->m_Image->GetBufferPointer() + + this->m_Image->ComputeOffset(index) ); + + index[0]=Ix+1; index[1]=Iy; index[2]=Iz; + m_RayIntersectionVoxels[1] = ( this->m_Image->GetBufferPointer() + + this->m_Image->ComputeOffset(index) ); + + index[0]=Ix; index[1]=Iy+1; index[2]=Iz; + m_RayIntersectionVoxels[2] = ( this->m_Image->GetBufferPointer() + + this->m_Image->ComputeOffset(index) ); + + index[0]=Ix+1; index[1]=Iy+1; index[2]=Iz; + m_RayIntersectionVoxels[3] = ( this->m_Image->GetBufferPointer() + + this->m_Image->ComputeOffset(index) ); + + } + else + { + m_RayIntersectionVoxels[0] + = m_RayIntersectionVoxels[1] + = m_RayIntersectionVoxels[2] + = m_RayIntersectionVoxels[3] = NULL; + } + break; + } + + default: + { + itk::ExceptionObject err(__FILE__, __LINE__); + err.SetLocation( ITK_LOCATION ); + err.SetDescription( "The ray traversal direction is unset " + "- InitialiseVoxelPointers()."); + throw err; + return; + } + } +} + +/* ----------------------------------------------------------------------- + IncrementVoxelPointers() - Increment the voxel pointers + ----------------------------------------------------------------------- */ + +template +void +RayCastHelper +::IncrementVoxelPointers(void) +{ + double xBefore = m_Position3Dvox[0]; + double yBefore = m_Position3Dvox[1]; + double zBefore = m_Position3Dvox[2]; + + m_Position3Dvox[0] += m_VoxelIncrement[0]; + m_Position3Dvox[1] += m_VoxelIncrement[1]; + m_Position3Dvox[2] += m_VoxelIncrement[2]; + + int dx = ((int) m_Position3Dvox[0]) - ((int) xBefore); + int dy = ((int) m_Position3Dvox[1]) - ((int) yBefore); + int dz = ((int) m_Position3Dvox[2]) - ((int) zBefore); + + m_RayIntersectionVoxelIndex[0] += dx; + m_RayIntersectionVoxelIndex[1] += dy; + m_RayIntersectionVoxelIndex[2] += dz; + + int totalRayVoxelPlanes + = dx + dy*m_NumberOfVoxelsInX + dz*m_NumberOfVoxelsInX*m_NumberOfVoxelsInY; + + m_RayIntersectionVoxels[0] += totalRayVoxelPlanes; + m_RayIntersectionVoxels[1] += totalRayVoxelPlanes; + m_RayIntersectionVoxels[2] += totalRayVoxelPlanes; + m_RayIntersectionVoxels[3] += totalRayVoxelPlanes; +} + + +/* ----------------------------------------------------------------------- + GetCurrentIntensity() - Get the intensity of the current ray point. + ----------------------------------------------------------------------- */ + +template +double +RayCastHelper +::GetCurrentIntensity(void) const +{ + double a, b, c, d; + double y, z; + + if (! m_ValidRay) + { + return 0; + } + a = (double) (*m_RayIntersectionVoxels[0]); + b = (double) (*m_RayIntersectionVoxels[1] - a); + c = (double) (*m_RayIntersectionVoxels[2] - a); + d = (double) (*m_RayIntersectionVoxels[3] - a - b - c); + + switch( m_TraversalDirection ) + { + case TRANSVERSE_IN_X: + { + y = m_Position3Dvox[1] - vcl_floor(m_Position3Dvox[1]); + z = m_Position3Dvox[2] - vcl_floor(m_Position3Dvox[2]); + break; + } + case TRANSVERSE_IN_Y: + { + y = m_Position3Dvox[0] - vcl_floor(m_Position3Dvox[0]); + z = m_Position3Dvox[2] - vcl_floor(m_Position3Dvox[2]); + break; + } + case TRANSVERSE_IN_Z: + { + y = m_Position3Dvox[0] - vcl_floor(m_Position3Dvox[0]); + z = m_Position3Dvox[1] - vcl_floor(m_Position3Dvox[1]); + break; + } + default: + { + itk::ExceptionObject err(__FILE__, __LINE__); + err.SetLocation( ITK_LOCATION ); + err.SetDescription( "The ray traversal direction is unset " + "- GetCurrentIntensity()."); + throw err; + return 0; + } + } + + return a + b*y + c*z + d*y*z; +} + +/* ----------------------------------------------------------------------- + IncrementIntensities() - Increment the intensities of the current ray point + ----------------------------------------------------------------------- */ + +template +void +RayCastHelper +::IncrementIntensities(double increment) +{ + short inc = (short) vcl_floor(increment + 0.5); + + if (! m_ValidRay) + { + return; + } + *m_RayIntersectionVoxels[0] += inc; + *m_RayIntersectionVoxels[1] += inc; + *m_RayIntersectionVoxels[2] += inc; + *m_RayIntersectionVoxels[3] += inc; + + return; +} + + +/* ----------------------------------------------------------------------- + IntegrateAboveThreshold() - Integrate intensities above a threshold. + ----------------------------------------------------------------------- */ + +template +bool +RayCastHelper +::IntegrateAboveThreshold(double &integral, double threshold) +{ + double intensity; +// double posn3D_x, posn3D_y, posn3D_z; + + integral = 0.; + + // Check if this is a valid ray + + if (! m_ValidRay) + { + return false; + } + /* Step along the ray as quickly as possible + integrating the interpolated intensities. */ + + for (m_NumVoxelPlanesTraversed=0; + m_NumVoxelPlanesTraversedGetCurrentIntensity(); + + if (intensity > threshold) + { + integral += intensity - threshold; + } + this->IncrementVoxelPointers(); + } + + /* The ray passes through the volume one plane of voxels at a time, + however, if its moving diagonally the ray points will be further + apart so account for this by scaling by the distance moved. */ + + integral *= this->GetRayPointSpacing(); + + return true; +} + +/* ----------------------------------------------------------------------- + ZeroState() - Set the default (zero) state of the object + ----------------------------------------------------------------------- */ + +template +void +RayCastHelper +::ZeroState() +{ + int i; + + m_ValidRay = false; + + m_NumberOfVoxelsInX = 0; + m_NumberOfVoxelsInY = 0; + m_NumberOfVoxelsInZ = 0; + + m_VoxelDimensionInX = 0; + m_VoxelDimensionInY = 0; + m_VoxelDimensionInZ = 0; + + for (i=0; i<3; i++) + { + m_CurrentRayPositionInMM[i] = 0.; + } + for (i=0; i<3; i++) + { + m_RayDirectionInMM[i] = 0.; + } + for (i=0; i<3; i++) + { + m_RayVoxelStartPosition[i] = 0.; + } + for (i=0; i<3; i++) + { + m_RayVoxelEndPosition[i] = 0.; + } + for (i=0; i<3; i++) + { + m_VoxelIncrement[i] = 0.; + } + m_TraversalDirection = UNDEFINED_DIRECTION; + + m_TotalRayVoxelPlanes = 0; + m_NumVoxelPlanesTraversed = -1; + + for (i=0; i<4; i++) + { + m_RayIntersectionVoxels[i] = 0; + } + for (i=0; i<3; i++) + { + m_RayIntersectionVoxelIndex[i] = 0; + } +} +}; // end of anonymous namespace + + +namespace itk +{ + +/************************************************************************** + * + * + * Rest of this code is the actual RayCastInterpolateImageFunctionWithOrigin + * class + * + * + **************************************************************************/ + +/* ----------------------------------------------------------------------- + Constructor + ----------------------------------------------------------------------- */ + +template +RayCastInterpolateImageFunctionWithOrigin< TInputImage, TCoordRep > +::RayCastInterpolateImageFunctionWithOrigin() +{ + m_Threshold = 0.; + + m_FocalPoint[0] = 0.; + m_FocalPoint[1] = 0.; + m_FocalPoint[2] = 0.; +} + + +/* ----------------------------------------------------------------------- + PrintSelf + ----------------------------------------------------------------------- */ + +template +void +RayCastInterpolateImageFunctionWithOrigin< TInputImage, TCoordRep > +::PrintSelf(std::ostream& os, Indent indent) const +{ + this->Superclass::PrintSelf(os,indent); + + os << indent << "Threshold: " << m_Threshold << std::endl; + os << indent << "FocalPoint: " << m_FocalPoint << std::endl; + os << indent << "Transform: " << m_Transform.GetPointer() << std::endl; + os << indent << "Interpolator: " << m_Interpolator.GetPointer() << std::endl; + +} + +/* ----------------------------------------------------------------------- + Evaluate at image index position + ----------------------------------------------------------------------- */ + +template +typename RayCastInterpolateImageFunctionWithOrigin< TInputImage, TCoordRep > +::OutputType +RayCastInterpolateImageFunctionWithOrigin< TInputImage, TCoordRep > +::Evaluate( const PointType& point ) const +{ + double integral = 0; + + OutputPointType transformedFocalPoint + = m_Transform->TransformPoint( m_FocalPoint ); + + DirectionType direction = transformedFocalPoint - point; + + RayCastHelper ray; + ray.SetImage( this->m_Image ); + ray.ZeroState(); + ray.Initialise(); + + // (Aviv) Added support for images with non-zero origin + // ray.SetRay(point, direction); + ray.SetRay(point - this->m_Image->GetOrigin().GetVectorFromOrigin(), direction); + ray.IntegrateAboveThreshold(integral, m_Threshold); + + return ( static_cast( integral )); +} + +template +typename RayCastInterpolateImageFunctionWithOrigin< TInputImage, TCoordRep > +::OutputType +RayCastInterpolateImageFunctionWithOrigin< TInputImage, TCoordRep > +::EvaluateAtContinuousIndex( const ContinuousIndexType& index ) const +{ + OutputPointType point; + this->m_Image->TransformContinuousIndexToPhysicalPoint(index, point); + + return this->Evaluate( point ); +} + +} // namespace itk + + +#endif diff --git a/itk/itkVTKImageToImageFilter.h b/itk/itkVTKImageToImageFilter.h new file mode 100644 index 0000000..b11b4b0 --- /dev/null +++ b/itk/itkVTKImageToImageFilter.h @@ -0,0 +1,107 @@ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkVTKImageToImageFilter.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:32:01 $ + Version: $Revision: 1.1 $ + + Copyright (c) 2002 Insight Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __itkVTKImageToImageFilter_h +#define __itkVTKImageToImageFilter_h + +#include "itkVTKImageImport.h" +#include "vtkImageExport.h" +#include "vtkImageData.h" + +#ifndef vtkFloatingPointType +#define vtkFloatingPointType float +#endif + +namespace itk +{ + +/** \class VTKImageToImageFilter + * \brief Converts a VTK image into an ITK image and plugs a + * vtk data pipeline to an ITK datapipeline. + * + * This class puts together an itkVTKImageImporter and a vtkImageExporter. + * It takes care of the details related to the connection of ITK and VTK + * pipelines. The User will perceive this filter as an adaptor to which + * a vtkImage can be plugged as input and an itk::Image is produced as + * output. + * + * \ingroup ImageFilters + */ +template +class ITK_EXPORT VTKImageToImageFilter : public ProcessObject +{ +public: + /** Standard class typedefs. */ + typedef VTKImageToImageFilter Self; + typedef ProcessObject Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(VTKImageToImageFilter, ProcessObject); + + /** Some typedefs. */ + typedef TOutputImage OutputImageType; + typedef typename OutputImageType::ConstPointer OutputImagePointer; + typedef VTKImageImport< OutputImageType > ImporterFilterType; + typedef typename ImporterFilterType::Pointer ImporterFilterPointer; + + /** Get the output in the form of a vtkImage. + This call is delegated to the internal vtkImageImporter filter */ + const OutputImageType * GetOutput() const; + + /** Set the input in the form of a vtkImageData */ + void SetInput( vtkImageData * ); + + /** Return the internal VTK image exporter filter. + This is intended to facilitate users the access + to methods in the exporter */ + vtkImageExport * GetExporter() const; + + /** Return the internal ITK image importer filter. + This is intended to facilitate users the access + to methods in the importer */ + ImporterFilterType * GetImporter() const; + + /** This call delegate the update to the importer */ + void Update(); + +protected: + VTKImageToImageFilter(); + virtual ~VTKImageToImageFilter(); + +private: + VTKImageToImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + ImporterFilterPointer m_Importer; + vtkImageExport * m_Exporter; + +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkVTKImageToImageFilter.txx" +#endif + +#endif + + + diff --git a/itk/itkVTKImageToImageFilter.txx b/itk/itkVTKImageToImageFilter.txx new file mode 100644 index 0000000..b06ccd8 --- /dev/null +++ b/itk/itkVTKImageToImageFilter.txx @@ -0,0 +1,144 @@ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkVTKImageToImageFilter.txx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:32:01 $ + Version: $Revision: 1.1 $ + + Copyright (c) 2002 Insight Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef _itkVTKImageToImageFilter_txx +#define _itkVTKImageToImageFilter_txx + +#include "itkVTKImageToImageFilter.h" + +namespace itk +{ + + + +/** + * Constructor + */ +template +VTKImageToImageFilter +::VTKImageToImageFilter() +{ + + m_Exporter = vtkImageExport::New(); + + m_Importer = ImporterFilterType::New(); + + m_Importer->SetUpdateInformationCallback( m_Exporter->GetUpdateInformationCallback()); + m_Importer->SetPipelineModifiedCallback( m_Exporter->GetPipelineModifiedCallback()); + m_Importer->SetWholeExtentCallback( m_Exporter->GetWholeExtentCallback()); + m_Importer->SetSpacingCallback( m_Exporter->GetSpacingCallback()); + m_Importer->SetOriginCallback( m_Exporter->GetOriginCallback()); + m_Importer->SetScalarTypeCallback( m_Exporter->GetScalarTypeCallback()); + m_Importer->SetNumberOfComponentsCallback( m_Exporter->GetNumberOfComponentsCallback()); + m_Importer->SetPropagateUpdateExtentCallback( m_Exporter->GetPropagateUpdateExtentCallback()); + m_Importer->SetUpdateDataCallback( m_Exporter->GetUpdateDataCallback()); + m_Importer->SetDataExtentCallback( m_Exporter->GetDataExtentCallback()); + m_Importer->SetBufferPointerCallback( m_Exporter->GetBufferPointerCallback()); + m_Importer->SetCallbackUserData( m_Exporter->GetCallbackUserData()); + +} + + + + +/** + * Destructor + */ +template +VTKImageToImageFilter +::~VTKImageToImageFilter() +{ + if ( m_Exporter ) + { + m_Exporter->Delete(); + m_Exporter = 0; + } +} + + + +/** + * Set a vtkImageData as input + */ +template +void +VTKImageToImageFilter +::SetInput( vtkImageData * inputImage ) +{ + m_Exporter->SetInput( inputImage ); +} + + + +/** + * Get an itk::Image as output + */ +template +const typename VTKImageToImageFilter::OutputImageType * +VTKImageToImageFilter +::GetOutput() const +{ + return m_Importer->GetOutput(); +} + + + + +/** + * Get the exporter filter + */ +template +vtkImageExport * +VTKImageToImageFilter +::GetExporter() const +{ + return m_Exporter; +} + + + +/** + * Get the importer filter + */ +template +typename VTKImageToImageFilter::ImporterFilterType * +VTKImageToImageFilter +::GetImporter() const +{ + return m_Importer; +} + + + + +/** + * Delegate the Update to the importer + */ +template +void +VTKImageToImageFilter +::Update() +{ + m_Importer->Update(); +} + + + + +} // end namespace itk + +#endif + diff --git a/make_meta.sh b/make_meta.sh new file mode 100755 index 0000000..29a496e --- /dev/null +++ b/make_meta.sh @@ -0,0 +1,19 @@ +#!/bin/bash +#This script creates the files necessary for developement: vim tags files, doxygen documentation, ... +ROOT_DIR=$(pwd) +echo $ROOT_DIR +#ROOT_DIR=${HOME}/workspace/vv +cd ${ROOT_DIR} +[ "$1" = "--full" ] && doxygen clitk.doxygen& + +for i in $(find $(pwd) -type d | grep -v "^\.$") +do + cd $i && [ -n "$(find . -maxdepth 1 -name '*.c??')" ] && + { + rm .vimrc + ln -s ${ROOT_DIR}/.vimrc . + ctags -R --languages=c,c++ --exclude=build --langmap=c++:.c++.cc.cp.cpp.cxx.h.h++.hh.hp.hpp.hxx.C.H.txx --exclude=doc --exclude=tests_jef ${ROOT_DIR} & + } +done +wait +echo "done!" diff --git a/tools/.cvsignore b/tools/.cvsignore new file mode 100644 index 0000000..59659d6 --- /dev/null +++ b/tools/.cvsignore @@ -0,0 +1 @@ +*_ggo.* diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt new file mode 100644 index 0000000..a1a6f92 --- /dev/null +++ b/tools/CMakeLists.txt @@ -0,0 +1,78 @@ + +#========================================================= +INCLUDE(${PROJECT_SOURCE_DIR}/cmake/common.cmake) +#========================================================= + +ADD_EXECUTABLE(clitkDicomInfo clitkDicomInfo.cxx clitkDicomInfo_ggo.c) +TARGET_LINK_LIBRARIES(clitkDicomInfo ITKIO clitkCommon) + +ADD_EXECUTABLE(clitkImageInfo clitkImageInfo.cxx clitkImageInfo_ggo.c) +TARGET_LINK_LIBRARIES(clitkImageInfo ITKIO clitkCommon) + +ADD_EXECUTABLE(clitkImageConvert clitkImageConvert.cxx clitkImageConvert_ggo.c ) +TARGET_LINK_LIBRARIES(clitkImageConvert ITKIO clitkCommon clitkFilters) + +ADD_EXECUTABLE(clitkImageResample clitkImageResample.cxx clitkImageResample_ggo.c) +TARGET_LINK_LIBRARIES(clitkImageResample ITKIO clitkCommon clitkFilters) + +ADD_EXECUTABLE(clitkVFResample clitkVFResample.cxx clitkImageResample_ggo.c) +TARGET_LINK_LIBRARIES(clitkVFResample ITKIO clitkCommon clitkFilters) + +ADD_EXECUTABLE(clitkImageArithm clitkImageArithm.cxx clitkImageArithm_ggo.c) +TARGET_LINK_LIBRARIES(clitkImageArithm ITKIO ITKStatistics clitkCommon clitkFilters) + +ADD_EXECUTABLE(clitkImageCreate clitkImageCreate.cxx clitkImageCreate_ggo.c) +TARGET_LINK_LIBRARIES(clitkImageCreate ITKIO ITKStatistics clitkCommon) + +ADD_EXECUTABLE(clitkImageFillRegion clitkImageFillRegion.cxx clitkImageFillRegion_ggo.c) +TARGET_LINK_LIBRARIES(clitkImageFillRegion ITKIO ITKStatistics clitkCommon +clitkFilters) + +ADD_EXECUTABLE(clitkZeroVF clitkZeroVF.cxx clitkZeroVF_ggo.c +clitkZeroVFGenericFilter.cxx) +TARGET_LINK_LIBRARIES(clitkZeroVF ITKIO ITKStatistics clitkCommon ) + +ADD_EXECUTABLE(clitkImageExtractLine clitkImageExtractLine.cxx clitkImageExtractLine_ggo.c) +TARGET_LINK_LIBRARIES(clitkImageExtractLine ITKIO ITKStatistics clitkCommon) + +ADD_EXECUTABLE(clitkSplitImage clitkSplitImage.cxx clitkSplitImage_ggo.c + ) +TARGET_LINK_LIBRARIES(clitkSplitImage ITKBasicFilters ITKIO clitkCommon +clitkFilters) + +ADD_EXECUTABLE(clitkVFMerge clitkVFMerge.cxx clitkVFMerge_ggo.c) +TARGET_LINK_LIBRARIES(clitkVFMerge ITKBasicFilters ITKIO clitkCommon ) + +ADD_EXECUTABLE(clitkWriteDicomSeries clitkWriteDicomSeries.cxx clitkWriteDicomSeries_ggo.c) +TARGET_LINK_LIBRARIES(clitkWriteDicomSeries ITKIO clitkCommon clitkFilters) + +ADD_EXECUTABLE(clitkAverageTemporalDimension clitkAverageTemporalDimension.cxx clitkAverageTemporalDimension_ggo.c) +TARGET_LINK_LIBRARIES(clitkAverageTemporalDimension ITKIO clitkCommon +clitkFilters) + +ADD_EXECUTABLE(clitkWarpImage clitkWarpImage.cxx clitkWarpImage_ggo.c +clitkWarpImageGenericFilter.cxx) +TARGET_LINK_LIBRARIES(clitkWarpImage ITKBasicFilters ITKIO clitkCommon +) + +ADD_EXECUTABLE(clitkInvertVF clitkInvertVF.cxx clitkInvertVF_ggo.c) +TARGET_LINK_LIBRARIES(clitkInvertVF ITKIO clitkCommon clitkFilters) + +ADD_EXECUTABLE(clitkAffineTransform clitkAffineTransform.cxx clitkAffineTransform_ggo.c) +TARGET_LINK_LIBRARIES(clitkAffineTransform clitkCommon ITKIO clitkFilters) + +ADD_EXECUTABLE(clitkSignalMeanPositionTracking clitkSignalMeanPositionTracking.cxx clitkSignalMeanPositionFilter.cxx clitkEllipse.cxx clitkSignalMeanPositionTracking_ggo.c) +TARGET_LINK_LIBRARIES(clitkSignalMeanPositionTracking clitkCommon ITKIO fftw3) + +ADD_EXECUTABLE(clitkSignalFilter clitkSignalFilter.cxx clitkSignalFilter_ggo.c) +TARGET_LINK_LIBRARIES(clitkSignalFilter ITKIO clitkCommon fftw3) + +ADD_EXECUTABLE(clitkSetBackground clitkSetBackground.cxx +clitkSetBackgroundGenericFilter.cxx clitkSetBackground_ggo.c) +TARGET_LINK_LIBRARIES(clitkSetBackground clitkCommon ITKIO ) + +ADD_EXECUTABLE(clitkGuerreroVentilation clitkGuerreroVentilation.cxx + clitkGuerreroVentilation_ggo.c +) +TARGET_LINK_LIBRARIES(clitkGuerreroVentilation clitkCommon ITKIO ITKBasicFilters +clitkFilters) diff --git a/tools/clitkAffineTransform.cxx b/tools/clitkAffineTransform.cxx new file mode 100644 index 0000000..3717b6b --- /dev/null +++ b/tools/clitkAffineTransform.cxx @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + ------------------------------------------------------------------------*/ + +/* ================================================= + * @file clitkAffineTransform.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk +#include "clitkAffineTransform_ggo.h" +#include "clitkIO.h" +#include "clitkAffineTransformGenericFilter.h" + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkAffineTransform, args_info); + CLITK_INIT; + + // Filter + typedef clitk::AffineTransformGenericFilter FilterType; + FilterType::Pointer genericFilter = FilterType::New(); + + genericFilter->SetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +}// end main + +//-------------------------------------------------------------------- diff --git a/tools/clitkAffineTransform.ggo b/tools/clitkAffineTransform.ggo new file mode 100644 index 0000000..ac8c2d0 --- /dev/null +++ b/tools/clitkAffineTransform.ggo @@ -0,0 +1,31 @@ +#File clitkAffineTransform.ggo +Package "clitkAffineTransform" +version "1.0" +purpose "Resample with or without affine transform of 2D, 3D, 4D images or vector fields" + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off + +section "I/O" +option "input" i "Input image filename" string yes +option "output" o "Output image filename" string yes +option "like" l "Resample output this image (size, spacing,origin)" string no + +section "Options" +option "size" - "New output size if different from input" int no multiple +option "spacing" - "New output spacing if different from input" double no multiple +option "origin" - "New output origin if different from input" double no multiple +option "matrix" m "Affine matrix (homogene) filename" string no +option "pad" - "Edge padding value" double no default="0.0" + +section "Interpolation" +option "interp" - "Interpolation: 0=NN, 1=Linear, 2=BSpline, 3=BLUT" int no default="1" +option "interpOrder" - "Order if BLUT or BSpline (0-5)" int no default="3" +option "interpSF" - "Sampling factor if BLUT" int no default="20" +option "interpVF" - "Interpolation: 0=NN, 1=Linear, 2=BSpline, 3=BLUT" int no default="1" +option "interpVFOrder" - "Order if BLUT or BSpline (0-5)" int no default="3" +option "interpVFSF" - "Sampling factor if BLUT" int no default="20" + + + + diff --git a/tools/clitkAffineTransformGenericFilter.cxx b/tools/clitkAffineTransformGenericFilter.cxx new file mode 100644 index 0000000..828e829 --- /dev/null +++ b/tools/clitkAffineTransformGenericFilter.cxx @@ -0,0 +1,23 @@ +#ifndef clitkAffineTransformGenericFilter_cxx +#define clitkAffineTransformGenericFilter_cxx + +/* ================================================= + * @file clitkAffineTransformGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkAffineTransformGenericFilter.h" + + +namespace clitk +{ + + + +} //end clitk + +#endif //#define clitkAffineTransformGenericFilter_cxx diff --git a/tools/clitkAffineTransformGenericFilter.h b/tools/clitkAffineTransformGenericFilter.h new file mode 100644 index 0000000..2be7ec6 --- /dev/null +++ b/tools/clitkAffineTransformGenericFilter.h @@ -0,0 +1,105 @@ +#ifndef clitkAffineTransformGenericFilter_h +#define clitkAffineTransformGenericFilter_h + +/* ================================================= + * @file clitkAffineTransformGenericFilter.h + * @author jefvdmb@gmail.com + * @date + * + * @brief + * + ===================================================*/ + + +// clitk include +#include "clitkIO.h" +#include "clitkCommon.h" +#include "clitkAffineTransform_ggo.h" +#include "clitkTransformUtilities.h" +#include "clitkGenericInterpolator.h" +#include "clitkGenericVectorInterpolator.h" + +//itk include +#include "itkLightObject.h" +#include "itkAffineTransform.h" +#include "itkResampleImageFilter.h" +#include "itkVectorResampleImageFilter.h" + + +namespace clitk +{ + + + template + class ITK_EXPORT AffineTransformGenericFilter : public itk::LightObject + { + public: + //---------------------------------------- + // ITK + //---------------------------------------- + typedef AffineTransformGenericFilter Self; + typedef itk::LightObject Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( AffineTransformGenericFilter, LightObject ); + + + //---------------------------------------- + // Typedefs + //---------------------------------------- + + + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetArgsInfo(const args_info_type & a) + { + m_ArgsInfo=a; + m_Verbose=m_ArgsInfo.verbose_flag; + m_InputFileName=m_ArgsInfo.input_arg; + } + + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(); + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + AffineTransformGenericFilter(); + ~AffineTransformGenericFilter() {}; + + + //---------------------------------------- + // Templated members + //---------------------------------------- + template void UpdateWithDim(std::string PixelType, int Components); + template void UpdateWithDimAndPixelType(); + template void UpdateWithDimAndVectorType(); + + //---------------------------------------- + // Data members + //---------------------------------------- + args_info_type m_ArgsInfo; + bool m_Verbose; + std::string m_InputFileName; + + }; + + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkAffineTransformGenericFilter.txx" +#endif + +#endif // #define clitkAffineTransformGenericFilter_h diff --git a/tools/clitkAffineTransformGenericFilter.txx b/tools/clitkAffineTransformGenericFilter.txx new file mode 100644 index 0000000..958b2fa --- /dev/null +++ b/tools/clitkAffineTransformGenericFilter.txx @@ -0,0 +1,342 @@ +#ifndef clitkAffineTransformGenericFilter_txx +#define clitkAffineTransformGenericFilter_txx + +/* ================================================= + * @file clitkAffineTransformGenericFilter.txx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +namespace clitk +{ + + //----------------------------------------------------------- + // Constructor + //----------------------------------------------------------- + template + AffineTransformGenericFilter::AffineTransformGenericFilter() + { + m_Verbose=false; + m_InputFileName=""; + } + + + //----------------------------------------------------------- + // Update + //----------------------------------------------------------- + template + void AffineTransformGenericFilter::Update() + { + // Read the Dimension and PixelType + int Dimension, Components; + std::string PixelType; + ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType, Components); + + + // Call UpdateWithDim + if(Dimension==2) UpdateWithDim<2>(PixelType, Components); + else if(Dimension==3) UpdateWithDim<3>(PixelType, Components); + else if (Dimension==4)UpdateWithDim<4>(PixelType, Components); + else + { + std::cout<<"Error, Only for 2, 3 or 4 Dimensions!!!"< + template + void + AffineTransformGenericFilter::UpdateWithDim(std::string PixelType, int Components) + { + if (m_Verbose) std::cout << "Image was detected to be "<(); + } + // else if(PixelType == "unsigned_short"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_short..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + + else if (PixelType == "unsigned_char"){ + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_char..." << std::endl; + UpdateWithDimAndPixelType(); + } + + // else if (PixelType == "char"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed_char..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + else { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and float..." << std::endl; + UpdateWithDimAndPixelType(); + } + } + + else if (Components==3) + { + if (m_Verbose) std::cout << "Launching transform in "<< Dimension <<"D and 3D float (DVF)" << std::endl; + UpdateWithDimAndVectorType >(); + } + + else std::cerr<<"Number of components is "< + template + void + AffineTransformGenericFilter::UpdateWithDimAndPixelType() + { + + // ImageTypes + typedef itk::Image InputImageType; + typedef itk::Image OutputImageType; + + // Read the input + typedef itk::ImageFileReader InputReaderType; + typename InputReaderType::Pointer reader = InputReaderType::New(); + reader->SetFileName( m_InputFileName); + reader->Update(); + typename InputImageType::Pointer input= reader->GetOutput(); + + //Filter + typedef itk::ResampleImageFilter< InputImageType,OutputImageType > ResampleFilterType; + typename ResampleFilterType::Pointer resampler = ResampleFilterType::New(); + + // Matrix + typename itk::Matrix matrix; + if (m_ArgsInfo.matrix_given) + { + matrix= clitk::ReadMatrix(m_ArgsInfo.matrix_arg); + if (m_Verbose) std::cout<<"Reading the matrix..."< rotationMatrix=clitk::GetRotationalPartMatrix(matrix); + typename itk::Vector translationPart= clitk::GetTranslationPartMatrix(matrix); + + // Transform + typedef itk::AffineTransform AffineTransformType; + typename AffineTransformType::Pointer affineTransform=AffineTransformType::New(); + affineTransform->SetMatrix(rotationMatrix); + affineTransform->SetTranslation(translationPart); + + // Interp + typedef clitk::GenericInterpolator GenericInterpolatorType; + typename GenericInterpolatorType::Pointer genericInterpolator=GenericInterpolatorType::New(); + genericInterpolator->SetArgsInfo(m_ArgsInfo); + + // Properties + if (m_ArgsInfo.like_given) + { + typename InputReaderType::Pointer likeReader=InputReaderType::New(); + likeReader->SetFileName(m_ArgsInfo.like_arg); + likeReader->Update(); + resampler->SetOutputParametersFromImage(likeReader->GetOutput()); + } + else + { + //Size + typename OutputImageType::SizeType outputSize; + if (m_ArgsInfo.size_given) + { + for(unsigned int i=0; i< Dimension; i++) + outputSize[i]=m_ArgsInfo.size_arg[i]; + } + else outputSize=input->GetLargestPossibleRegion().GetSize(); + std::cout<<"Setting the size to "<GetSpacing(); + std::cout<<"Setting the spacing to "<GetOrigin(); + std::cout<<"Setting the origin to "<SetSize( outputSize ); + resampler->SetOutputSpacing( outputSpacing ); + resampler->SetOutputOrigin( outputOrigin ); + + } + + resampler->SetInput( input ); + resampler->SetTransform( affineTransform ); + resampler->SetInterpolator( genericInterpolator->GetInterpolatorPointer()); + resampler->SetDefaultPixelValue( static_cast(m_ArgsInfo.pad_arg) ); + + try + { + resampler->Update(); + } + catch(itk::ExceptionObject) + { + std::cerr<<"Error resampling the image"<GetOutput(); + + // Output + typedef itk::ImageFileWriter WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(m_ArgsInfo.output_arg); + writer->SetInput(output); + writer->Update(); + + } + + //------------------------------------------------------------------- + // Update with the number of dimensions and the pixeltype (components) + //------------------------------------------------------------------- + template + template + void AffineTransformGenericFilter::UpdateWithDimAndVectorType() + { + // ImageTypes + typedef itk::Image InputImageType; + typedef itk::Image OutputImageType; + + // Read the input + typedef itk::ImageFileReader InputReaderType; + typename InputReaderType::Pointer reader = InputReaderType::New(); + reader->SetFileName( m_InputFileName); + reader->Update(); + typename InputImageType::Pointer input= reader->GetOutput(); + + //Filter + typedef itk::VectorResampleImageFilter< InputImageType,OutputImageType, double > ResampleFilterType; + typename ResampleFilterType::Pointer resampler = ResampleFilterType::New(); + + // Matrix + typename itk::Matrix matrix; + if (m_ArgsInfo.matrix_given) + matrix= clitk::ReadMatrix(m_ArgsInfo.matrix_arg); + else + matrix.SetIdentity(); + if (m_Verbose) std::cout<<"Using the following matrix:"< rotationMatrix=clitk::GetRotationalPartMatrix(matrix); + typename itk::Vector translationPart= clitk::GetTranslationPartMatrix(matrix); + + // Transform + typedef itk::AffineTransform AffineTransformType; + typename AffineTransformType::Pointer affineTransform=AffineTransformType::New(); + affineTransform->SetMatrix(rotationMatrix); + affineTransform->SetTranslation(translationPart); + + // Interp + typedef clitk::GenericVectorInterpolator GenericInterpolatorType; + typename GenericInterpolatorType::Pointer genericInterpolator=GenericInterpolatorType::New(); + genericInterpolator->SetArgsInfo(m_ArgsInfo); + + // Properties + if (m_ArgsInfo.like_given) + { + typename InputReaderType::Pointer likeReader=InputReaderType::New(); + likeReader->SetFileName(m_ArgsInfo.like_arg); + likeReader->Update(); + resampler->SetSize( likeReader->GetOutput()->GetLargestPossibleRegion().GetSize() ); + resampler->SetOutputSpacing( likeReader->GetOutput()->GetSpacing() ); + resampler->SetOutputOrigin( likeReader->GetOutput()->GetOrigin() ); + } + else + { + //Size + typename OutputImageType::SizeType outputSize; + if (m_ArgsInfo.size_given) + { + for(unsigned int i=0; i< Dimension; i++) + outputSize[i]=m_ArgsInfo.size_arg[i]; + } + else outputSize=input->GetLargestPossibleRegion().GetSize(); + std::cout<<"Setting the size to "<GetSpacing(); + std::cout<<"Setting the spacing to "<GetOrigin(); + std::cout<<"Setting the origin to "<SetSize( outputSize ); + resampler->SetOutputSpacing( outputSpacing ); + resampler->SetOutputOrigin( outputOrigin ); + + } + + resampler->SetInput( input ); + resampler->SetTransform( affineTransform ); + resampler->SetInterpolator( genericInterpolator->GetInterpolatorPointer()); + resampler->SetDefaultPixelValue( static_cast(m_ArgsInfo.pad_arg) ); + + try + { + resampler->Update(); + } + catch(itk::ExceptionObject) + { + std::cerr<<"Error resampling the image"<GetOutput(); + + // Output + typedef itk::ImageFileWriter WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(m_ArgsInfo.output_arg); + writer->SetInput(output); + writer->Update(); + + } + + +} //end clitk + +#endif //#define clitkAffineTransformGenericFilter_txx diff --git a/tools/clitkAverageTemporalDimension.cxx b/tools/clitkAverageTemporalDimension.cxx new file mode 100644 index 0000000..fb50ce3 --- /dev/null +++ b/tools/clitkAverageTemporalDimension.cxx @@ -0,0 +1,46 @@ +/*------------------------------------------------------------------------ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + ------------------------------------------------------------------------*/ + +/* ================================================= + * @file clitkAverageTemporalDimension.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk +#include "clitkAverageTemporalDimension_ggo.h" +#include "clitkIO.h" +#include "clitkAverageTemporalDimensionGenericFilter.h" + + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkAverageTemporalDimension, args_info); + CLITK_INIT; + + // Filter + typedef clitk::AverageTemporalDimensionGenericFilter FilterType; + FilterType::Pointer genericFilter = FilterType::New(); + + genericFilter->SetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +}// end main + +//-------------------------------------------------------------------- diff --git a/tools/clitkAverageTemporalDimension.ggo b/tools/clitkAverageTemporalDimension.ggo new file mode 100644 index 0000000..f8b3342 --- /dev/null +++ b/tools/clitkAverageTemporalDimension.ggo @@ -0,0 +1,12 @@ +#File clitkAverageTemporalDimension.ggo +Package "clitkAverageTemporalDimension" +version "1.0" +purpose "Average the last dimension to an (n-1)D image. Input is either nD or multiple (n-1)D image or DVF" + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off + +option "input" i "Input image filename" string yes multiple +option "output" o "Output image filename" string yes + + diff --git a/tools/clitkAverageTemporalDimensionGenericFilter.cxx b/tools/clitkAverageTemporalDimensionGenericFilter.cxx new file mode 100644 index 0000000..da9a9c6 --- /dev/null +++ b/tools/clitkAverageTemporalDimensionGenericFilter.cxx @@ -0,0 +1,24 @@ +#ifndef clitkAverageTemporalDimensionGenericFilter_cxx +#define clitkAverageTemporalDimensionGenericFilter_cxx + +/* ================================================= + * @file clitkAverageTemporalDimensionGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkAverageTemporalDimensionGenericFilter.h" + + +namespace clitk +{ + + + + +} //end clitk + +#endif //#define clitkAverageTemporalDimensionGenericFilter_cxx diff --git a/tools/clitkAverageTemporalDimensionGenericFilter.h b/tools/clitkAverageTemporalDimensionGenericFilter.h new file mode 100644 index 0000000..08820b2 --- /dev/null +++ b/tools/clitkAverageTemporalDimensionGenericFilter.h @@ -0,0 +1,97 @@ +#ifndef clitkAverageTemporalDimensionGenericFilter_h +#define clitkAverageTemporalDimensionGenericFilter_h + +/* ================================================= + * @file clitkAverageTemporalDimensionGenericFilter.h + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk include +#include "clitkIO.h" +#include "clitkCommon.h" +#include "clitkAverageTemporalDimension_ggo.h" + +//itk include +#include "itkLightObject.h" + +namespace clitk +{ + + template + class ITK_EXPORT AverageTemporalDimensionGenericFilter : public itk::LightObject + { + public: + //---------------------------------------- + // ITK + //---------------------------------------- + typedef AverageTemporalDimensionGenericFilter Self; + typedef itk::LightObject Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( AverageTemporalDimensionGenericFilter, LightObject ); + + + //---------------------------------------- + // Typedefs + //---------------------------------------- + + + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetArgsInfo(const args_info_type & a) + { + m_ArgsInfo=a; + m_Verbose=m_ArgsInfo.verbose_flag; + m_InputFileName=m_ArgsInfo.input_arg[0]; + } + + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(); + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + AverageTemporalDimensionGenericFilter(); + ~AverageTemporalDimensionGenericFilter() {}; + + + //---------------------------------------- + // Templated members + //---------------------------------------- + template void UpdateWithDim(const std::string PixelType, const int Components); + template void UpdateWithDimAndPixelType(); + + + //---------------------------------------- + // Data members + //---------------------------------------- + args_info_type m_ArgsInfo; + bool m_Verbose; + std::string m_InputFileName; + + }; + + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkAverageTemporalDimensionGenericFilter.txx" +#endif + +#endif // #define clitkAverageTemporalDimensionGenericFilter_h diff --git a/tools/clitkAverageTemporalDimensionGenericFilter.txx b/tools/clitkAverageTemporalDimensionGenericFilter.txx new file mode 100644 index 0000000..525f0dd --- /dev/null +++ b/tools/clitkAverageTemporalDimensionGenericFilter.txx @@ -0,0 +1,227 @@ +#ifndef clitkAverageTemporalDimensionGenericFilter_txx +#define clitkAverageTemporalDimensionGenericFilter_txx + +/* ================================================= + * @file clitkAverageTemporalDimensionGenericFilter.txx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +namespace clitk +{ + + //----------------------------------------------------------- + // Constructor + //----------------------------------------------------------- + template + AverageTemporalDimensionGenericFilter::AverageTemporalDimensionGenericFilter() + { + m_Verbose=false; + m_InputFileName=""; + } + + + //----------------------------------------------------------- + // Update + //----------------------------------------------------------- + template + void AverageTemporalDimensionGenericFilter::Update() + { + // Read the Dimension and PixelType + int Dimension, Components; + std::string PixelType; + ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType, Components); + + + // Call UpdateWithDim + if (m_ArgsInfo.input_given>1) Dimension+=1; + if(Dimension==2) UpdateWithDim<2>(PixelType, Components); + else if(Dimension==3)UpdateWithDim<3>(PixelType, Components); + else if (Dimension==4)UpdateWithDim<4>(PixelType, Components); + else + { + std::cout<<"Error, Only for 2, 3 or 4D!!!"< + template + void + AverageTemporalDimensionGenericFilter::UpdateWithDim(const std::string PixelType, const int Components) + { + if (m_Verbose) std::cout << "Image was detected to be "<(); + } + // else if(PixelType == "unsigned_short"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_short..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + + else if (PixelType == "unsigned_char"){ + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_char..." << std::endl; + UpdateWithDimAndPixelType(); + } + + // else if (PixelType == "char"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed_char..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + else { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and float..." << std::endl; + UpdateWithDimAndPixelType(); + } + } + + // else if (Components==2) + // { + // if (m_Verbose) std::cout << "Launching transform in "<< Dimension <<"D and 3D float (DVF)" << std::endl; + // UpdateWithDimAndPixelType >(); + // } + + else if (Components==3) + { + if (m_Verbose) std::cout << "Launching transform in "<< Dimension <<"D and 3D float (DVF)" << std::endl; + UpdateWithDimAndPixelType >(); + } + + // else if (Components==4) + // { + // if (m_Verbose) std::cout << "Launching transform in "<< Dimension <<"D and 3D float (DVF)" << std::endl; + // UpdateWithDimAndPixelType >(); + // } + else std::cerr<<"Number of components is "< + template + void + AverageTemporalDimensionGenericFilter::UpdateWithDimAndPixelType() + { + + // ImageTypes + typedef itk::Image InputImageType; + typedef itk::Image OutputImageType; + typename InputImageType::Pointer input; + + if (m_ArgsInfo.input_given ==1 ) + { + // Read the input + typedef itk::ImageFileReader InputReaderType; + typename InputReaderType::Pointer reader = InputReaderType::New(); + reader->SetFileName( m_InputFileName); + reader->Update(); + input= reader->GetOutput(); + } + + else + { + // Read and join multiple inputs + if (m_Verbose) std::cout< filenames; + for(unsigned int i=0; i ImageReaderType; + typename ImageReaderType::Pointer reader= ImageReaderType::New(); + reader->SetFileNames(filenames); + reader->Update(); + input =reader->GetOutput(); + } + + + // Output properties + typename OutputImageType::RegionType region; + typename OutputImageType::RegionType::SizeType size; + typename OutputImageType::IndexType index; + typename OutputImageType::SpacingType spacing; + typename OutputImageType::PointType origin; + typename InputImageType::RegionType region4D=input->GetLargestPossibleRegion(); + typename InputImageType::RegionType::SizeType size4D=region4D.GetSize(); + typename InputImageType::IndexType index4D=region4D.GetIndex(); + typename InputImageType::SpacingType spacing4D=input->GetSpacing(); + typename InputImageType::PointType origin4D=input->GetOrigin(); + + for (unsigned int i=0; i< Dimension-1; i++) + { + size[i]=size4D[i]; + index[i]=index4D[i]; + spacing[i]=spacing4D[i]; + origin[i]=origin4D[i]; + } + region.SetSize(size); + region.SetIndex(index); + typename OutputImageType::Pointer output= OutputImageType::New(); + output->SetRegions(region); + output->SetSpacing(spacing); + output->SetOrigin(origin); + output->Allocate(); + + + // Region iterators + typedef itk::ImageRegionIterator IteratorType; + std::vector iterators(size4D[Dimension-1]); + for (unsigned int i=0; i< size4D[Dimension-1]; i++) + { + typename InputImageType::RegionType regionIt=region4D; + typename InputImageType::RegionType::SizeType sizeIt=regionIt.GetSize(); + sizeIt[Dimension-1]=1; + regionIt.SetSize(sizeIt); + typename InputImageType::IndexType indexIt=regionIt.GetIndex(); + indexIt[Dimension-1]=i; + regionIt.SetIndex(indexIt); + iterators[i]=IteratorType(input, regionIt); + } + + typedef itk::ImageRegionIterator OutputIteratorType; + OutputIteratorType avIt(output, output->GetLargestPossibleRegion()); + + // Average + PixelType vector; + PixelType zeroVector=itk::NumericTraits::Zero; + //zeroVector.Fill(0.0); + while (!(iterators[0]).IsAtEnd()) + { + vector=zeroVector; + for (unsigned int i=0; i WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(m_ArgsInfo.output_arg); + writer->SetInput(output); + writer->Update(); + + } + + +}//end clitk + +#endif //#define clitkAverageTemporalDimensionGenericFilter_txx diff --git a/tools/clitkCorrelationRatioImageToImageMetric.h b/tools/clitkCorrelationRatioImageToImageMetric.h new file mode 100644 index 0000000..d82d960 --- /dev/null +++ b/tools/clitkCorrelationRatioImageToImageMetric.h @@ -0,0 +1,165 @@ + +/*========================================================================= + + Program: clitk + Module: $RCSfile: clitkCorrelationRatioImageToImageMetric.h + Language: C++ + Date: $Date: 2010/01/06 13:31:56 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef __clitkCorrelationRatioImageToImageMetric_h +#define __clitkCorrelationRatioImageToImageMetric_h + +/** + * @file clitkCorrelationRatioImageToImageMetric.h + * @author Jef Vandemeulebroucke + * @date July 30 18:14:53 2007 + * + * @brief Compute the correlation ratio between 2 images + * + * + */ + +/* This computes the correlation ratio between 2 images + * + * This class is templated over the FixedImage type and the MovingImage + * type. + * + * The fixed and moving images are set via methods SetFixedImage() and + * SetMovingImage(). This metric makes use of user specified Transform and + * Interpolator. The Transform is used to map points from the fixed image to + * the moving image domain. The Interpolator is used to evaluate the image + * intensity at user specified geometric points in the moving image. + * The Transform and Interpolator are set via methods SetTransform() and + * SetInterpolator(). + * + * The method GetValue() computes of the mutual information + * while method GetValueAndDerivative() computes + * both the mutual information and its derivatives with respect to the + * transform parameters. + * + * The calculations are based on the method of Alexis Roche. + * + * The number of intensity bins used can be set through the SetNumberOfBins() method + * + * On Initialize(), we find the min and max intensities in the fixed image and compute the width of + * the intensity bins. The data structures which hold the bins and related measures are initialised. + */ + + +#include "itkImageToImageMetric.h" +#include "itkCovariantVector.h" +#include "itkPoint.h" + +using namespace itk; +namespace clitk +{ + +template < class TFixedImage, class TMovingImage > +class ITK_EXPORT CorrelationRatioImageToImageMetric: + public ImageToImageMetric< TFixedImage, TMovingImage> +{ +public: + + /** Standard class typedefs. */ + typedef CorrelationRatioImageToImageMetric Self; + typedef ImageToImageMetric Superclass; + + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(CorrelationRatioImageToImageMetric, ImageToImageMetric); + + + /** Types transferred from the base class */ + typedef typename Superclass::RealType RealType; + typedef typename Superclass::TransformType TransformType; + typedef typename Superclass::TransformPointer TransformPointer; + typedef typename Superclass::TransformParametersType TransformParametersType; + typedef typename Superclass::TransformJacobianType TransformJacobianType; + typedef typename Superclass::GradientPixelType GradientPixelType; + + typedef typename Superclass::MeasureType MeasureType; + typedef typename Superclass::DerivativeType DerivativeType; + typedef typename Superclass::FixedImageType FixedImageType; + typedef typename Superclass::MovingImageType MovingImageType; + typedef typename Superclass::FixedImageConstPointer FixedImageConstPointer; + typedef typename Superclass::MovingImageConstPointer MovingImageConstPointer; + + + /** + * Initialize the Metric by + * (1) making sure that all the components are present and plugged + * together correctly, + * (3) allocate memory for bin data structures. */ + virtual void Initialize(void) throw ( ExceptionObject ); + + /** Get the derivatives of the match measure. */ + void GetDerivative( const TransformParametersType & parameters, + DerivativeType & derivative ) const; + + /** Get the value for single valued optimizers. */ + MeasureType GetValue( const TransformParametersType & parameters ) const; + + /** Get value and derivatives for multiple valued optimizers. */ + void GetValueAndDerivative( const TransformParametersType & parameters, + MeasureType& Value, DerivativeType& Derivative ) const; + + /** Number of bins to used in the calculation. Typical value is 50. */ + itkSetClampMacro( NumberOfBins, unsigned long, + 1, NumericTraits::max() ); + itkGetConstReferenceMacro( NumberOfBins, unsigned long); + +protected: + CorrelationRatioImageToImageMetric(); + virtual ~CorrelationRatioImageToImageMetric() {}; + +private: + CorrelationRatioImageToImageMetric(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + + //the min and max in the fixed image intensity range + double m_FixedImageMin; + + //The bin size in intensity + double m_FixedImageBinSize; + + //The number of pixels in the fixed image bins are stored in a vector + mutable std::vector m_NumberOfPixelsCountedPerBin; + + //The mMSVPB and the mSMVPB are stored in vectors of realtype + typedef float ValueType; + typedef std::vector MeasurePerBinType; + mutable MeasurePerBinType m_mMSVPB; + mutable MeasurePerBinType m_mSMVPB; + unsigned long m_NumberOfBins; + + +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkCorrelationRatioImageToImageMetric.txx" +#endif + +#endif + + + diff --git a/tools/clitkCorrelationRatioImageToImageMetric.txx b/tools/clitkCorrelationRatioImageToImageMetric.txx new file mode 100644 index 0000000..f95574f --- /dev/null +++ b/tools/clitkCorrelationRatioImageToImageMetric.txx @@ -0,0 +1,482 @@ +/*========================================================================= + + Program: clitk + Module: $RCSfile: clitkCorrelationRatioImageToImageMetric.h + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef _clitkCorrelationRatioImageToImageMetric_txx +#define _clitkCorrelationRatioImageToImageMetric_txx + +/** + * @file clitkCorrelationRatioImageToImageMetric.txx + * @author Jef Vandemeulebroucke + * @date July 30 18:14:53 2007 + * + * @brief Compute the correlation ratio between 2 images + * + * + */ + +#include "clitkCorrelationRatioImageToImageMetric.h" +#include "itkImageRegionConstIteratorWithIndex.h" +#include "itkImageRegionConstIterator.h" +#include "itkImageRegionIterator.h" + +namespace clitk +{ + +/* + * Constructor + */ +template +CorrelationRatioImageToImageMetric +::CorrelationRatioImageToImageMetric() +{ + m_NumberOfBins = 50; + +} + +template +void +CorrelationRatioImageToImageMetric +::Initialize(void) throw ( ExceptionObject ) +{ + + this->Superclass::Initialize(); + + // Compute the minimum and maximum for the FixedImage over the FixedImageRegion. + // We can't use StatisticsImageFilter to do this because the filter computes the min/max for the largest possible region + double fixedImageMin = NumericTraits::max(); + double fixedImageMax = NumericTraits::NonpositiveMin(); + + typedef ImageRegionConstIterator FixedIteratorType; + FixedIteratorType fixedImageIterator( + this->m_FixedImage, this->GetFixedImageRegion() ); + + for ( fixedImageIterator.GoToBegin(); + !fixedImageIterator.IsAtEnd(); ++fixedImageIterator ) + { + + double sample = static_cast( fixedImageIterator.Get() ); + + if ( sample < fixedImageMin ) + { + fixedImageMin = sample; + } + + if ( sample > fixedImageMax ) + { + fixedImageMax = sample; + } + } + + // Compute binsize for the fixedImage + m_FixedImageBinSize = ( fixedImageMax - fixedImageMin ) / m_NumberOfBins; + m_FixedImageMin=fixedImageMin; + //Allocate mempry and initialise the fixed image bin + m_NumberOfPixelsCountedPerBin.resize( m_NumberOfBins, 0 ); + m_mMSVPB.resize( m_NumberOfBins, 0.0 ); + m_mSMVPB.resize( m_NumberOfBins, 0.0 ); +} + + +/* + * Get the match Measure + */ +template +typename CorrelationRatioImageToImageMetric::MeasureType +CorrelationRatioImageToImageMetric +::GetValue( const TransformParametersType & parameters ) const +{ + + itkDebugMacro("GetValue( " << parameters << " ) "); + + FixedImageConstPointer fixedImage = this->m_FixedImage; + + if( !fixedImage ) + { + itkExceptionMacro( << "Fixed image has not been assigned" ); + } + + typedef itk::ImageRegionConstIteratorWithIndex FixedIteratorType; + + + FixedIteratorType ti( fixedImage, this->GetFixedImageRegion() ); + + typename FixedImageType::IndexType index; + + MeasureType measure = itk::NumericTraits< MeasureType >::Zero; + + this->m_NumberOfPixelsCounted = 0; + this->SetTransformParameters( parameters ); + + + //temporary measures for the calculation + RealType mSMV=0; + RealType mMSV=0; + + while(!ti.IsAtEnd()) + { + + index = ti.GetIndex(); + + typename Superclass::InputPointType inputPoint; + fixedImage->TransformIndexToPhysicalPoint( index, inputPoint ); + + // Verify that the point is in the fixed Image Mask + if( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) + { + ++ti; + continue; + } + + typename Superclass::OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint ); + + //Verify that the point is in the moving Image Mask + if( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) + { + ++ti; + continue; + } + + // Verify is the interpolated value is in the buffer + if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) + { + //Accumulate calculations for the correlation ratio + //For each pixel the is in both masks and the buffer we adapt the following measures: + //movingMeanSquaredValue mMSV; movingSquaredMeanValue mSMV; + //movingMeanSquaredValuePerBin[i] mSMVPB; movingSquaredMeanValuePerBin[i] mSMVPB + //NumberOfPixelsCounted, NumberOfPixelsCountedPerBin[i] + + //get the value of the moving image + const RealType movingValue = this->m_Interpolator->Evaluate( transformedPoint ); + // for the variance of the overlapping moving image we accumulate the following measures + const RealType movingSquaredValue=movingValue*movingValue; + mMSV+=movingSquaredValue; + mSMV+=movingValue; + + //get the fixed value + const RealType fixedValue = ti.Get(); + + //check in which bin the fixed value belongs, get the index + const double fixedImageBinTerm = (fixedValue - m_FixedImageMin) / m_FixedImageBinSize; + const unsigned int fixedImageBinIndex = static_cast( vcl_floor(fixedImageBinTerm ) ); + //adapt the measures per bin + this->m_mMSVPB[fixedImageBinIndex]+=movingSquaredValue; + this->m_mSMVPB[fixedImageBinIndex]+=movingValue; + //increase the fixed image bin and the total pixel count + this->m_NumberOfPixelsCountedPerBin[fixedImageBinIndex]+=1; + this->m_NumberOfPixelsCounted++; + } + + ++ti; + } + + if( !this->m_NumberOfPixelsCounted ) + { + itkExceptionMacro(<<"All the points mapped to outside of the moving image"); + } + else + { + + //apdapt the measures per bin + for (unsigned int i=0; i< m_NumberOfBins; i++ ){ + if (this->m_NumberOfPixelsCountedPerBin[i]>0){ + measure+=(this->m_mMSVPB[i]-((this->m_mSMVPB[i]*this->m_mSMVPB[i])/this->m_NumberOfPixelsCountedPerBin[i])); + } + } + + //Normalize with the global measures + measure /= (mMSV-((mSMV*mSMV)/ this->m_NumberOfPixelsCounted)); + return measure; + + } +} + + + + + +/* + * Get the Derivative Measure + */ +template < class TFixedImage, class TMovingImage> +void +CorrelationRatioImageToImageMetric +::GetDerivative( const TransformParametersType & parameters, + DerivativeType & derivative ) const +{ + + itkDebugMacro("GetDerivative( " << parameters << " ) "); + + if( !this->GetGradientImage() ) + { + itkExceptionMacro(<<"The gradient image is null, maybe you forgot to call Initialize()"); + } + + FixedImageConstPointer fixedImage = this->m_FixedImage; + + if( !fixedImage ) + { + itkExceptionMacro( << "Fixed image has not been assigned" ); + } + + const unsigned int ImageDimension = FixedImageType::ImageDimension; + + + typedef itk::ImageRegionConstIteratorWithIndex< + FixedImageType> FixedIteratorType; + + typedef itk::ImageRegionConstIteratorWithIndex< + ITK_TYPENAME Superclass::GradientImageType> GradientIteratorType; + + + FixedIteratorType ti( fixedImage, this->GetFixedImageRegion() ); + + typename FixedImageType::IndexType index; + + this->m_NumberOfPixelsCounted = 0; + + this->SetTransformParameters( parameters ); + + const unsigned int ParametersDimension = this->GetNumberOfParameters(); + derivative = DerivativeType( ParametersDimension ); + derivative.Fill( itk::NumericTraits::Zero ); + + ti.GoToBegin(); + + while(!ti.IsAtEnd()) + { + + index = ti.GetIndex(); + + typename Superclass::InputPointType inputPoint; + fixedImage->TransformIndexToPhysicalPoint( index, inputPoint ); + + if( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) + { + ++ti; + continue; + } + + typename Superclass::OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint ); + + if( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) + { + ++ti; + continue; + } + + if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) + { + const RealType movingValue = this->m_Interpolator->Evaluate( transformedPoint ); + + const TransformJacobianType & jacobian = + this->m_Transform->GetJacobian( inputPoint ); + + + const RealType fixedValue = ti.Value(); + this->m_NumberOfPixelsCounted++; + const RealType diff = movingValue - fixedValue; + + // Get the gradient by NearestNeighboorInterpolation: + // which is equivalent to round up the point components. + typedef typename Superclass::OutputPointType OutputPointType; + typedef typename OutputPointType::CoordRepType CoordRepType; + typedef ContinuousIndex + MovingImageContinuousIndexType; + + MovingImageContinuousIndexType tempIndex; + this->m_MovingImage->TransformPhysicalPointToContinuousIndex( transformedPoint, tempIndex ); + + typename MovingImageType::IndexType mappedIndex; + for( unsigned int j = 0; j < MovingImageType::ImageDimension; j++ ) + { + mappedIndex[j] = static_cast( vnl_math_rnd( tempIndex[j] ) ); + } + + const GradientPixelType gradient = + this->GetGradientImage()->GetPixel( mappedIndex ); + + for(unsigned int par=0; par::Zero; + for(unsigned int dim=0; dimm_NumberOfPixelsCounted ) + { + itkExceptionMacro(<<"All the points mapped to outside of the moving image"); + } + else + { + for(unsigned int i=0; im_NumberOfPixelsCounted; + } + } + +} + + +/* + * Get both the match Measure and the Derivative Measure + */ +template +void +CorrelationRatioImageToImageMetric +::GetValueAndDerivative(const TransformParametersType & parameters, + MeasureType & value, DerivativeType & derivative) const +{ + + itkDebugMacro("GetValueAndDerivative( " << parameters << " ) "); + + if( !this->GetGradientImage() ) + { + itkExceptionMacro(<<"The gradient image is null, maybe you forgot to call Initialize()"); + } + + FixedImageConstPointer fixedImage = this->m_FixedImage; + + if( !fixedImage ) + { + itkExceptionMacro( << "Fixed image has not been assigned" ); + } + + const unsigned int ImageDimension = FixedImageType::ImageDimension; + + typedef itk::ImageRegionConstIteratorWithIndex< + FixedImageType> FixedIteratorType; + + typedef itk::ImageRegionConstIteratorWithIndex< + ITK_TYPENAME Superclass::GradientImageType> GradientIteratorType; + + + FixedIteratorType ti( fixedImage, this->GetFixedImageRegion() ); + + typename FixedImageType::IndexType index; + + MeasureType measure = NumericTraits< MeasureType >::Zero; + + this->m_NumberOfPixelsCounted = 0; + + this->SetTransformParameters( parameters ); + + const unsigned int ParametersDimension = this->GetNumberOfParameters(); + derivative = DerivativeType( ParametersDimension ); + derivative.Fill( NumericTraits::Zero ); + + ti.GoToBegin(); + + while(!ti.IsAtEnd()) + { + + index = ti.GetIndex(); + + typename Superclass::InputPointType inputPoint; + fixedImage->TransformIndexToPhysicalPoint( index, inputPoint ); + + if( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) + { + ++ti; + continue; + } + + typename Superclass::OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint ); + + if( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) + { + ++ti; + continue; + } + + if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) + { + const RealType movingValue = this->m_Interpolator->Evaluate( transformedPoint ); + + const TransformJacobianType & jacobian = + this->m_Transform->GetJacobian( inputPoint ); + + + const RealType fixedValue = ti.Value(); + this->m_NumberOfPixelsCounted++; + + const RealType diff = movingValue - fixedValue; + + measure += diff * diff; + + // Get the gradient by NearestNeighboorInterpolation: + // which is equivalent to round up the point components. + typedef typename Superclass::OutputPointType OutputPointType; + typedef typename OutputPointType::CoordRepType CoordRepType; + typedef ContinuousIndex + MovingImageContinuousIndexType; + + MovingImageContinuousIndexType tempIndex; + this->m_MovingImage->TransformPhysicalPointToContinuousIndex( transformedPoint, tempIndex ); + + typename MovingImageType::IndexType mappedIndex; + for( unsigned int j = 0; j < MovingImageType::ImageDimension; j++ ) + { + mappedIndex[j] = static_cast( vnl_math_rnd( tempIndex[j] ) ); + } + + const GradientPixelType gradient = + this->GetGradientImage()->GetPixel( mappedIndex ); + + for(unsigned int par=0; par::Zero; + for(unsigned int dim=0; dimm_NumberOfPixelsCounted ) + { + itkExceptionMacro(<<"All the points mapped to outside of the moving image"); + } + else + { + for(unsigned int i=0; im_NumberOfPixelsCounted; + } + measure /= this->m_NumberOfPixelsCounted; + } + + value = measure; + +} + +} // end namespace itk + + +#endif + diff --git a/tools/clitkDicomInfo.cxx b/tools/clitkDicomInfo.cxx new file mode 100644 index 0000000..ff17d76 --- /dev/null +++ b/tools/clitkDicomInfo.cxx @@ -0,0 +1,54 @@ +/*------------------------------------------------------------------------- + +Program: clitk +Module: $RCSfile: clitkDicomInfo.cxx,v $ +Language: C++ +Date: $Date: 2010/01/06 13:31:56 $ +Version: $Revision: 1.1 $ + +Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de +l'Image). All rights reserved. See Doc/License.txt or +http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +-------------------------------------------------------------------------*/ + +/** + ------------------------------------------------- + * @file clitkDicomInfo.cxx + * @author Laurent ZAGNI + * @date 27 Jul 2006 + -------------------------------------------------*/ + +// clitk includes +#include "clitkDicomInfo_ggo.h" +#include "clitkCommon.h" + +// itk (gdcm) include +#include "gdcmFile.h" + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // init command line + GGO(clitkDicomInfo, args_info); + + // check arg + if (args_info.inputs_num == 0) return 0; + + // Loop files + for(unsigned int i=0; iSetFileName(args_info.inputs[i]); + header->SetMaxSizeLoadEntry(16384); + header->Load(); + header->Print(); + } + + // this is the end my friend + return 0; +} +//-------------------------------------------------------------------- diff --git a/tools/clitkDicomInfo.ggo b/tools/clitkDicomInfo.ggo new file mode 100644 index 0000000..02351ea --- /dev/null +++ b/tools/clitkDicomInfo.ggo @@ -0,0 +1,5 @@ +# file DicomInfos.ggo +Package "clitk" +version "read and print Dicom header" + +option "config" - "Config file" string no diff --git a/tools/clitkEllipse.cxx b/tools/clitkEllipse.cxx new file mode 100644 index 0000000..a546b79 --- /dev/null +++ b/tools/clitkEllipse.cxx @@ -0,0 +1,285 @@ +/*========================================================================= + + Program: clitk + Module: $RCSfile: clitkEllipse.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:56 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "clitkEllipse.h" + +typedef itk::Vector Vector2d; +typedef itk::Vector Vector6d; +typedef itk::Matrix Matrix6x6d; +typedef itk::Matrix Matrix3x3d; + +//--------------------------------------------------------------------- +clitk::Ellipse::Ellipse():a((*this)[0]), b((*this)[1]), + c((*this)[2]), d((*this)[3]), + e((*this)[4]), f((*this)[5]) { +} +//--------------------------------------------------------------------- + + +//--------------------------------------------------------------------- +clitk::Ellipse::Ellipse(const Ellipse & e):a((*this)[0]), b((*this)[1]), + c((*this)[2]), d((*this)[3]), + e((*this)[4]), f((*this)[5]) { + for(int i=0; i<7; i++) (*this)[i] = e[i]; +} + +//--------------------------------------------------------------------- + + +//--------------------------------------------------------------------- +Vector2d clitk::Ellipse::ComputeCenter() { + // See http://mathworld.wolfram.com/Ellipse.html + // see Ruan 2008 + Vector2d center; + center[0] = (2*c*d - b*e)/(b*b-4*a*c); + center[1] = (2*a*e - b*d)/(b*b-4*a*c); + return center; +} +//--------------------------------------------------------------------- + + +//--------------------------------------------------------------------- +Vector2d clitk::Ellipse::ComputeSemiAxeLengths() { + // See http://www.geometrictools.com/Documentation/InformationAboutEllipses.pdf + Vector2d axis; + Vector2d center = ComputeCenter(); + double & k1 = center[0]; + double & k2 = center[1]; + double mu = 1.0/(a*k1*k1 + b*k1*k2 + c*k2*k2 - f); + double m11 = mu * a; + double m12 = mu * 0.5 * b; + double m22 = mu * c; + double l1 = ( (m11+m22) + sqrt((m11-m22)*(m11-m22)+4*m12*m12) )/2.0; + assert(l1>0.0); + axis[1] = 1.0/sqrt(l1); + double l2 = ((m11+m22)-sqrt((m11-m22)*(m11-m22)+4*m12*m12))/2.0; + assert(l2>0.0); + axis[0] = 1.0/sqrt(l2); + return axis; +} +//--------------------------------------------------------------------- + + +//--------------------------------------------------------------------- +double clitk::Ellipse::ComputeAngleInRad() { + // See http://www.geometrictools.com/Documentation/InformationAboutEllipses.pdf + double theta; + if (b==0) { + if (a extremaX(2); + std::vector extremaY(2); + double x0 = 0.0; + double y0 = 0.0; + extremaX[0] = extremaY[0] = numeric_limits::max(); + extremaX[1] = extremaY[1] = -numeric_limits::max(); + for(unsigned int i=0; i extremaX[1]) extremaX[1] = inputX[i]; + if (inputY[i] < extremaY[0]) extremaY[0] = inputY[i]; + if (inputY[i] > extremaY[1]) extremaY[1] = inputY[i]; + x0 += inputX[i]; + y0 += inputY[i]; + } + x0 /= n; + y0 /= n; + + // initialisation with an ellipse more small than real points extends + double ax1 = (extremaX[1]-extremaX[0])/2.0; + double ax2 = (extremaY[1]-extremaY[0])/2.0; + if (ax2 >= ax1) ax2 = 0.99*ax1; + SetCenterAndSemiAxes(x0, y0, ax1, ax2); + + // Initialisation of C + C.Fill(0.0); + C(0,0) = 0; C(0,1) = 0; C(0,2) = 2; + C(1,0) = 0; C(1,1) = -1; C(1,2) = 0; + C(2,0) = 2; C(2,1) = 0; C(2,2) = 0; + Ct = C.GetVnlMatrix().transpose(); + + // Compute initial S + UpdateSMatrix(0,n, inputX, inputY); +} +//--------------------------------------------------------------------- + + +//--------------------------------------------------------------------- +void clitk::Ellipse::CopyBlock(Matrix6x6d & out, const Matrix6x6d & in, + int ox, int oy, int l, double factor) { + for(int x=ox; xc) { + std::cerr << "Error major axis should be r1, not r2 (r1=" << r1 + << " r2=" << r2 << ")" << std::endl; + exit(0); + } + d = (-2.0*x0)/(r1*r1); + e = (-2.0*y0)/(r2*r2); + f = (x0*x0)/(r1*r1) + (y0*y0)/(r2*r2) - 1.0; + GetVnlVector().normalize(); +} +//--------------------------------------------------------------------- + + +//--------------------------------------------------------------------- +void clitk::Ellipse::UpdateSMatrix(unsigned int begin, unsigned int n, + clitk::Signal & inputX, clitk::Signal & inputY) { + // Initialisation of z + z.resize(n); + int j = 0; + for(unsigned int i=begin; i +#include +#include + +namespace clitk { + + //--------------------------------------------------------------------- + class Ellipse : public itk::Vector { + public: + typedef itk::Vector Vector2d; + typedef itk::Vector Vector6d; + typedef itk::Matrix Matrix6x6d; + typedef itk::Matrix Matrix3x3d; + + Ellipse(); + Ellipse(const Ellipse & e); + void InitialiseEllipseFitting(double eta, unsigned int n, clitk::Signal & inputX, clitk::Signal & inputY); + double EllipseFittingNextIteration(); + Vector2d ComputeCenter(); + Vector2d ComputeSemiAxeLengths(); + double ComputeAngleInRad(); + void SetCenterAndSemiAxes(double x0, double y0, double r1, double r2); + void Copy(const Vector6d & a); + double GetEta() { return mEta; } + void UpdateSMatrix(unsigned int begin, unsigned int n, + clitk::Signal & inputX, clitk::Signal & inputY); + + protected: + double mEta; + double & a; + double & b; + double & c; + double & d; + double & e; + double & f; + Matrix6x6d C; + Matrix6x6d Ct; + Matrix6x6d W; + Matrix6x6d Wt; + Matrix6x6d S; + Matrix6x6d Sinv; + Matrix6x6d St; + std::vector z; + clitk::Signal * mInputX; + clitk::Signal * mInputY; + + void CopyBlock(Matrix6x6d & out, const Matrix6x6d & in, + int ox, int oy, int l, double factor=1.0); + void CopyBlock(Matrix6x6d & out, const Matrix3x3d & in, + int ox, int oy, double factor=1.0); + Matrix3x3d GetBlock3x3(const Matrix6x6d & M, int x, int y); + + }; + //--------------------------------------------------------------------- + +} // end namespace + +#endif diff --git a/tools/clitkGuerreroVentilation.cxx b/tools/clitkGuerreroVentilation.cxx new file mode 100644 index 0000000..c234ec9 --- /dev/null +++ b/tools/clitkGuerreroVentilation.cxx @@ -0,0 +1,48 @@ +/*------------------------------------------------------------------------= + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + ------------------------------------------------------------------------=*/ + +/** + ------------------------------------------------= + * @file clitkGuerreroVentilation.cxx + * @author Joël Schaerer + * @date 20 April 2009 + ------------------------------------------------=*/ + +// clitk include +#include "clitkGuerreroVentilation_ggo.h" +#include "clitkGuerreroVentilationGenericFilter.h" +#include "clitkIO.h" + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkGuerreroVentilation, args_info); + CLITK_INIT; + + // Read image dimension + itk::ImageIOBase::Pointer header = clitk::readImageHeader(args_info.input_arg); + //unsigned int dim = header->GetNumberOfDimensions(); + + // Check parameters + // Main filter + clitk::GuerreroVentilationGenericFilter filter; + filter.SetInputFilename(args_info.input_arg); + filter.AddInputFilename(args_info.ref_arg); + filter.SetOutputFilename(args_info.output_arg); + filter.SetBloodCorrectionFactor(args_info.factor_arg); + filter.SetUseCorrectFormula(args_info.correct_flag); + filter.Update(); + + // this is the end my friend + return 0; +} // end main diff --git a/tools/clitkGuerreroVentilation.ggo b/tools/clitkGuerreroVentilation.ggo new file mode 100644 index 0000000..26a4ff8 --- /dev/null +++ b/tools/clitkGuerreroVentilation.ggo @@ -0,0 +1,13 @@ +#File clitkGuerreroVentilation.ggo +Package "clitkGuerreroVentilation" +version "1.0" +purpose "Compute the ventilation image from a motion compensated image and the reference (end-expiration) image" + + +option "config" - "Config file" string no +option "input" i "Input image filename" string yes +option "ref" r "Reference image filename" string yes +option "output" o "Output image base filename" string yes +option "factor" f "Blood mass correction factor" double yes +option "verbose" v "Verbose" flag off +option "correct" c "Use the correct formula instead of the original one" flag off diff --git a/tools/clitkImageArithm.cxx b/tools/clitkImageArithm.cxx new file mode 100644 index 0000000..0b7b36e --- /dev/null +++ b/tools/clitkImageArithm.cxx @@ -0,0 +1,110 @@ +/*------------------------------------------------------------------------- + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + -------------------------------------------------------------------------*/ + +#ifndef CLITKIMAGEARITHM_CXX +#define CLITKIMAGEARITHM_CXX + +/** + ------------------------------------------------- + * @file clitkImageArithm.cxx + * @author David Sarrut + * @date 23 Feb 2008 08:37:53 + -------------------------------------------------*/ + +// clitk include +#include "clitkImageArithm_ggo.h" +#include "clitkImageArithmGenericFilter.h" +#include "clitkIO.h" + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkImageArithm, args_info); + CLITK_INIT; + + // Check that we have either the 2nd image or the scalar + if ((args_info.input2_given) && (args_info.scalar_given)) { + std::cerr << "ERROR : you cannot provide both --scalar and --input2 option" << std::endl; + exit(-1); + } + if ((!args_info.input2_given) && (!args_info.scalar_given)) { + if (args_info.operation_arg < 5) { + std::cerr << "Such operation need the --scalar option." << std::endl; + exit(-1); + } + } + + // Read input image header1 to check image dimension + itk::ImageIOBase::Pointer header1 = clitk::readImageHeader(args_info.input1_arg); + unsigned int dim1 = header1->GetNumberOfDimensions(); + std::string pixelTypeName = header1->GetComponentTypeAsString(header1->GetComponentType()); + + // Options for arithm operation between 2 images + if (args_info.input2_given) { + + itk::ImageIOBase::Pointer header2 = clitk::readImageHeader(args_info.input2_arg); + unsigned int dim2 = header2->GetNumberOfDimensions(); + std::string pixelTypeName2 = header2->GetComponentTypeAsString(header1->GetComponentType()); + + // Check dimension + if (dim1 != dim2) { + std::cerr << "Images should have the same dimension : " <GetDimensions(1)<< std::endl; + std::cerr << "Dimensions X and Y of input2: = " << header2->GetDimensions(0) <<" "<< header2->GetDimensions(1)<< std::endl; + exit(-1); + } + }//end for + if (dim1 == 3) { + if (header1->GetDimensions(2) < header2->GetDimensions(2)) { + std::cerr << "ERROR: Z size in input1 is greater than in input2. " << std::endl; + std::cerr << "Size input1 : " << header1->GetDimensions(0) << " " << header1->GetDimensions(1)<< " " << header1->GetDimensions(2) << std::endl; + std::cerr << "Size input2 : " << header2->GetDimensions(0) << " " << header2->GetDimensions(1)<< " " << header2->GetDimensions(2) << std::endl; + } + } + } //end if operation between 2 images + + // Creation of a generic filter + clitk::ImageArithmGenericFilter::Pointer filter = clitk::ImageArithmGenericFilter::New(); + filter->AddInputFilename(args_info.input1_arg); + if (args_info.input2_given) filter->AddInputFilename(args_info.input2_arg); + else filter->SetScalar(args_info.scalar_arg); + //if (args_info.binary_given) filter->SetBinaryMaskFilename(args_info.binary_arg); + filter->SetTypeOfOperation(args_info.operation_arg); + filter->SetDefaultPixelValue(args_info.pixelValue_arg); + filter->SetOutputFilename(args_info.output_arg); + + // Go ! + filter->Update(); + + // this is the end my friend + return 0; +} // end main + +#endif //define CLITKIMAGEARITHM_CXX diff --git a/tools/clitkImageArithm.ggo b/tools/clitkImageArithm.ggo new file mode 100644 index 0000000..d3d5ef6 --- /dev/null +++ b/tools/clitkImageArithm.ggo @@ -0,0 +1,17 @@ +#File clitkImageArithm.ggo +Package "clitkImageArithm" +version "1.0" +purpose "Perform an arithmetic operation (+-*/ ...) using two images or using an image and a scalar value." + + +option "config" - "Config file" string no +option "input1" i "Input first image filename" string yes +option "input2" j "Input second image filename" string no +option "output" o "Output image filename" string yes + +option "scalar" s "Scalar value" double no +option "operation" t "Type of operation : \n With another image : 0=add, 1=multiply, 2=divide,\n 3=max, 4=min, 5=absdiff, 6=squareddiff, 7=difference, 8=relativ diff\n For 'scalar' : 0=add, 1=multiply, 2=inverse,\n 3=max, 4=min 5=absval 6=squareval\n 7=log 8=exp 9=sqrt" int default="0" no +option "pixelValue" - "Default value for NaN/Inf" double default="0.0" no +option "verbose" v "Verbose" flag off + +#option "binary" b "Mask for binary operation" string no diff --git a/tools/clitkImageConvert.cxx b/tools/clitkImageConvert.cxx new file mode 100644 index 0000000..ccae952 --- /dev/null +++ b/tools/clitkImageConvert.cxx @@ -0,0 +1,71 @@ +/*------------------------------------------------------------------------- + +Program: clitk +Module: $RCSfile: clitkImageConvert.cxx,v $ +Language: C++ +Date: $Date: 2010/01/06 13:31:56 $ +Version: $Revision: 1.1 $ + +Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de +l'Image). All rights reserved. See Doc/License.txt or +http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +-------------------------------------------------------------------------*/ + +#ifndef CLITKIMAGECONVERT_CXX +#define CLITKIMAGECONVERT_CXX + +/** + ------------------------------------------------- + * @file clitkImageConvert.cxx + * @author David Sarrut + * @date 03 Jul 2006 10:28:32 + -------------------------------------------------*/ + +// clitk include +#include "clitkImageConvert_ggo.h" +#include "clitkIO.h" +#include "clitkImageCommon.h" +#include "clitkImageConvertGenericFilter.h" + +//-------------------------------------------------------------------= +int main(int argc, char * argv[]) { + + // init command line + GGO(clitkImageConvert, args_info); + CLITK_INIT; + + // Get list of filenames + std::vector l; + for(unsigned int i=0; iSetInputFilenames(l); + filter->SetIOVerbose(args_info.verbose_flag); + filter->SetOutputFilename(args_info.output_arg); + if (args_info.type_given) filter->SetOutputPixelType(args_info.type_arg); + + // Go ! + filter->Update(); + + // this is the end my friend + return 0; +} +//-------------------------------------------------------------------= + +#endif /* end #define CLITKIMAGECONVERT_CXX */ + diff --git a/tools/clitkImageConvert.ggo b/tools/clitkImageConvert.ggo new file mode 100644 index 0000000..e3c7507 --- /dev/null +++ b/tools/clitkImageConvert.ggo @@ -0,0 +1,10 @@ +# file clitkImageConvert.ggo +Package "clitkImageConvert" +version "1.0" +purpose "Convert an image into another image.\n\tAllow to change the file format and/or the pixel type. \n\tKnown file formats 2D: jpeg png bmp tif mhd hdr vox dcm \n\tKnown file formats 3D: mhd vox hdr dcm\n\tKnown file formats 4D: mhd \n\tKnown images: 2D 3D or 4D, schar, uchar, short, ushort, int, float and double \nYou can also specify multiple inputs (i.e. \"-i a.mhd,b.mhd,c.mhd\" or \"a.mhd b.mhd ...\" without the '-i' option) having the same size and dimension to build a (n+1)D image." + +option "config" - "Config file" string no +option "input" i "Input image filename" string no multiple +option "output" o "Output image filename" string yes +option "type" t "Output type (float, ushort ...)" string no +option "verbose" v "Verbose" flag off diff --git a/tools/clitkImageCreate.cxx b/tools/clitkImageCreate.cxx new file mode 100644 index 0000000..21e6072 --- /dev/null +++ b/tools/clitkImageCreate.cxx @@ -0,0 +1,148 @@ +/*------------------------------------------------------------------------= + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + ------------------------------------------------------------------------=*/ + +#ifndef CLITKIMAGECREATE_CXX +#define CLITKIMAGECREATE_CXX + +/** + ------------------------------------------------= + * @file clitkImageCreate.cxx + * @author David Sarrut + * @date 14 Oct 2008 08:37:53 + ------------------------------------------------=*/ + +// clitk include +#include "clitkImageCreate_ggo.h" +#include "clitkCommon.h" +#include "clitkImageCommon.h" +#include "clitkIO.h" + +template +void NewFilledImage(int * size, float * spacing, double * origin, + double value,typename ImageType::Pointer output) +{ + static const unsigned int Dim = ImageType::GetImageDimension(); + typename ImageType::SizeType mSize; + mSize.Fill (0); + for(unsigned int i=0; iSetRegions(mRegion); + output->SetSpacing(mSpacing); + output->Allocate(); + typename ImageType::PointType mOrigin; + for(unsigned int i=0; iSetOrigin(mOrigin); + typedef typename ImageType::PixelType PixelType; + PixelType p = clitk::PixelTypeDownCast(value); + output->FillBuffer(p); +} + + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkImageCreate, args_info); + CLITK_INIT; + + // Check --like option + int dim; + if (args_info.like_given) { + itk::ImageIOBase::Pointer header = clitk::readImageHeader(args_info.like_arg); + dim = header->GetNumberOfDimensions(); + //mPixelTypeName = header->GetComponentTypeAsString(header->GetComponentType()); + //mNbOfComponents = header->GetNumberOfComponents(); + args_info.size_given = dim; + args_info.size_arg = new int[dim]; + args_info.spacing_given = dim; + args_info.spacing_arg = new float[dim]; + args_info.origin_given = dim; + args_info.origin_arg = new double[dim]; + + for(int i=0; iGetDimensions(i); + args_info.spacing_arg[i] = header->GetSpacing(i); + args_info.origin_arg[i]= header->GetOrigin(i); + } + } + + // Check dimension + if ((args_info.size_given > 4) || (args_info.size_given <2)) { + std::cerr << "ERROR : only 2D/3D/4D image ! Please give 2 or 3 or 4 number to the --size option." << std::endl; + exit(-1); + } + dim = args_info.size_given; + + // origin + std::vector origin; + origin.resize(dim); + for(int i=0; i spacing; + spacing.resize(dim); + if (args_info.spacing_given == 1) { + for(int i=0; i ImageType; + ImageType::Pointer output = ImageType::New(); + NewFilledImage(args_info.size_arg, &spacing[0], &origin[0], args_info.value_arg, output); + clitk::writeImage(output, args_info.output_arg); + } + if (dim == 3) { + const int Dim=3; + typedef itk::Image ImageType; + ImageType::Pointer output = ImageType::New(); + NewFilledImage(args_info.size_arg, &spacing[0], &origin[0], args_info.value_arg, output); + clitk::writeImage(output, args_info.output_arg); + } + if (dim == 4) { + const int Dim=4; + typedef itk::Image ImageType; + ImageType::Pointer output = ImageType::New(); + NewFilledImage(args_info.size_arg, &spacing[0], &origin[0], args_info.value_arg, output); + clitk::writeImage(output, args_info.output_arg); + } + + // this is the end my friend + return 0; +} // end main + +#endif //define CLITKIMAGEARITHM_CXX diff --git a/tools/clitkImageCreate.ggo b/tools/clitkImageCreate.ggo new file mode 100644 index 0000000..6ba482c --- /dev/null +++ b/tools/clitkImageCreate.ggo @@ -0,0 +1,21 @@ +#File clitkImageCreate.ggo +Package "clitkImageCreate" +version "1.0" +purpose "Create a new singled value filled image (pixeltype is float, use clitkImageConvert to change)." + +option "config" - "Config file" string no +option "output" o "Output image filename" string yes + +option "like" l "Size/spacing like this other image" string no + +option "size" - "Number of pixels of each coordinate" int no multiple +option "spacing" - "Spacing in mm between pixels" float no multiple +option "origin" - "Origin in mm" double no multiple + +option "value" - "Value for all voxels" float default="0.0" no +option "verbose" v "Verbose" flag off + +#option "random" r "Random fill" flag off +#option "max" - "Max random fill" double default="100.0" no +#option "min" - "Min random fill" double default="0.0" no + diff --git a/tools/clitkImageExtractLine.cxx b/tools/clitkImageExtractLine.cxx new file mode 100644 index 0000000..94590a0 --- /dev/null +++ b/tools/clitkImageExtractLine.cxx @@ -0,0 +1,121 @@ +/*------------------------------------------------------------------------- + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + -------------------------------------------------------------------------*/ + +#ifndef CLITKIMAGEEXTRACTLINE_CXX +#define CLITKIMAGEEXTRACTLINE_CXX + +/** + ------------------------------------------------- + * @file clitkImageExtractLine.cxx + * @author David Sarrut + * @date 23 Feb 2008 08:37:53 + -------------------------------------------------*/ + +// clitk include +#include "clitkImageExtractLine_ggo.h" +#include "clitkIO.h" +#include + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkImageExtractLine, args_info); + CLITK_INIT; + + // Declare main types + typedef float PixelType; + const unsigned int Dimension=3; + typedef itk::Image ImageType; + + // Check options + if (args_info.firstIndex_given != Dimension) { + std::cerr << "Please give " << Dimension << "values to --firstIndex option" << std::endl; + exit(0); + } + if (args_info.lastIndex_given != Dimension) { + std::cerr << "Please give " << Dimension << "values to --lastIndex option" << std::endl; + exit(0); + } + + // Read image + ImageType::Pointer input = clitk::readImage(args_info.input_arg, args_info.verbose_flag); + + // Get first and last index + typedef ImageType::IndexType IndexType; + IndexType firstIndex; + IndexType lastIndex; + ImageType::SpacingType spacing = input->GetSpacing(); + double length = 0.0; + for(unsigned int i=0; i depth; + std::vector values; + itk::LineConstIterator iter(input, firstIndex, lastIndex); + iter.GoToBegin(); + while (!iter.IsAtEnd()) { + values.push_back(iter.Get()); + ++iter; + } + double step = length/values.size(); + + // If isocenter is used + double isoDistance = 0.0; + if (args_info.isocenter_given) { // isoCenter is in mm + IndexType isoCenter; + for(unsigned int i=0; i + * @date 23 Feb 2008 + ------------------------------------------------=*/ + +// clitk include +#include "clitkImageFillRegion_ggo.h" +#include "clitkImageFillRegionGenericFilter.h" +#include "clitkIO.h" + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkImageFillRegion, args_info); + CLITK_INIT; + + // Read image dimension + itk::ImageIOBase::Pointer header = clitk::readImageHeader(args_info.input_arg); + unsigned int dim = header->GetNumberOfDimensions(); + + // Main filter + clitk::ImageFillRegionGenericFilter filter; + filter.SetInputFilename(args_info.input_arg); + filter.SetOutputFilename(args_info.output_arg); + filter.SetFillPixelValue(args_info.value_arg); + + if(!args_info.ellips_flag && !args_info.rect_flag) + { + std::cerr << "ERROR : No type of region specified!"<< std::endl; + exit(-1); + } + + if(args_info.ellips_flag && args_info.rect_flag) + { + std::cerr << "ERROR : Multiple types of regions specified!"<< std::endl; + exit(-1); + } + + if(args_info.rect_flag) + { + if (args_info.size_given && args_info.start_given) { + // Check parameters + if (args_info.size_given != dim) { + std::cerr << "ERROR : image has " << dim << "dimensions, --size should have the same number of values." << std::endl; + exit(-1); + } + if (args_info.start_given != dim) { + std::cerr << "ERROR : image has " << dim << "dimensions, --size should have the same number of values." << std::endl; + exit(-1); + } + filter.SetRegion(args_info.size_arg, args_info.start_arg); + } + else { + std::cerr << "ERROR : both size and start should be given!"<< std::endl; + exit(-1); + } + } + + if(args_info.ellips_flag) + { + + std::vector c, a; + if (args_info.center_given) + { + if (args_info.center_given != dim) + { + std::cerr << "ERROR : image has " << dim << "dimensions, --center should have the same number of values." << std::endl; + exit(-1); + } + for(unsigned int i=0; i + * @date 02 Jul 2006 + =================================================*/ + +// clitk include +#include "clitkImageInfo_ggo.h" +#include "clitkIO.h" + +//==================================================================== +int main(int argc, char * argv[]) { + + // init command line + GGO(clitkImageInfo, args_info); + CLITK_INIT; + + // check arg + if (args_info.inputs_num == 0) return 0; + + // read Header + for(unsigned int i=0; i + * @date 23 Feb 2008 08:37:53 + ------------------------------------------------=*/ + +// clitk +#include "clitkImageResample_ggo.h" +#include "clitkIO.h" +#include "clitkImageResampleGenericFilter.h" + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkImageResample, args_info); + CLITK_INIT; + + // Read input image header to check image dimension + itk::ImageIOBase::Pointer header = clitk::readImageHeader(args_info.input_arg); + unsigned int dim = header->GetNumberOfDimensions(); + std::string pixelTypeName = header->GetComponentTypeAsString(header->GetComponentType()); + + // Print image info if verbose + if (args_info.verbose_flag) { + std::cout << "Input image <" << args_info.input_arg << "> is "; + clitk::printImageHeader(header, std::cout); + std::cout << std::endl; + } + + // Get input size/spacing + std::vector inputSize; + std::vector inputSpacing; + inputSize.resize(dim); + inputSpacing.resize(dim); + for(unsigned int i=0; iGetSpacing(i); + inputSize[i] = header->GetDimensions(i); + } + + // Get options + std::vector outputSize; + std::vector outputSpacing; + outputSize.resize(dim); + outputSpacing.resize(dim); + + // Check options + if (!args_info.size_given && !args_info.spacing_given) { + std::cerr << "Please indicate output size or spacing." << std::endl; + exit(0); + } + + // Check options + if (args_info.size_given && args_info.spacing_given) { + std::cerr << "Please indicate only output size or spacing, not both." << std::endl; + exit(0); + } + + // Size is given and not spacing + if (args_info.size_given && !args_info.spacing_given) { + if (args_info.size_given != dim) { + std::cerr << "Input image is " << dim << "D, please give " << dim << " size numbers." << std::endl; + exit(0); + } + for(unsigned int i=0; i sigma; + sigma.resize(args_info.gauss_given); + std::copy(args_info.gauss_arg, args_info.gauss_arg+args_info.gauss_given, sigma.begin()); + if (args_info.gauss_given) { + if (args_info.gauss_given != dim) { + if (args_info.gauss_given == 1) { + sigma.resize(dim); + for(unsigned int i=0; iSetInputFilename(args_info.input_arg); + filter->SetOutputSize(outputSize); + filter->SetOutputSpacing(outputSpacing); + filter->SetInterpolationName(args_info.interp_arg); + filter->SetBSplineOrder(args_info.order_arg); + filter->SetBLUTSampling(args_info.sampling_arg); + if (args_info.gauss_given) + filter->SetGaussianSigma(sigma); + filter->SetOutputFilename(args_info.output_arg); + + // Go ! + filter->Update(); + + // this is the end my friend + return 0; +}// end main +//-------------------------------------------------------------------- + +#endif /* end #define CLITKIMAGERESAMPLE_CXX */ diff --git a/tools/clitkImageResample.ggo b/tools/clitkImageResample.ggo new file mode 100644 index 0000000..5d9dde5 --- /dev/null +++ b/tools/clitkImageResample.ggo @@ -0,0 +1,17 @@ +#File clitkImageResample.ggo +Package "clitkImageResample" +version "1.0" +purpose "Resample an image. You can specify the interpolation, you can apply a Gaussian filter before." + +option "config" - "Config file" string no +option "input" i "Input image filename" string yes +option "output" o "Output image filename" string yes +option "verbose" v "Verbose" flag off +option "interp" - "Interpolation type: {nn, linear, bspline, blut}" string no default="nn" +option "order" b "BSpline ordre (range 0-5)" int no default="3" +option "sampling" s "BLUT sampling value" int no default="30" +option "size" - "Number of pixels of each coordonate" int no multiple default="0" +option "spacing" - "Spacing in mm between pixels" float no multiple default="0.0" +option "gauss" g "Apply Gaussian before (sigma in mm)" float no multiple default="1.0" +option "default" d "Default pixel value" float no default = "0.0" + diff --git a/tools/clitkImageWarp.ggo b/tools/clitkImageWarp.ggo new file mode 100644 index 0000000..a6c8853 --- /dev/null +++ b/tools/clitkImageWarp.ggo @@ -0,0 +1,16 @@ +#File clitkImageWarp.ggo +#Author: Jef Vandemeulebroucke +#Date : Tue 13 August 19.35 + +Package "clitk" +Version "Read an Image (short, char or float; 2D or 3D) and a vector field (float, 2D or 3D) and deform the input through backward or forward mapping." + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off +option "input" i "Input image filename" string yes +option "output" o "Output image filename" string yes +option "vf" - "Vector field filename" string yes +option "forward" f "Use forward warping (only linear interp)" flag off +option "spacing" s "The output spacing: 0=like the VF, 1= like the input image (linear interpolation of the VF prior to warp)" int no default="0" +option "interp" - "Type of interpolation used for the warping: 0=nearest neighbor, 1= linear, 2= cubic Bspline" int no default="1" +option "pad" - "Edge padding value" float no default="0.0" diff --git a/tools/clitkInvertVF.cxx b/tools/clitkInvertVF.cxx new file mode 100644 index 0000000..2360adf --- /dev/null +++ b/tools/clitkInvertVF.cxx @@ -0,0 +1,46 @@ +/*------------------------------------------------------------------------ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + ------------------------------------------------------------------------*/ + +/* ================================================= + * @file clitkInvertVF.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk +#include "clitkInvertVF_ggo.h" +#include "clitkIO.h" +#include "clitkInvertVFGenericFilter.h" + + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkInvertVF, args_info); + CLITK_INIT; + + // Filter + typedef clitk::InvertVFGenericFilter FilterType; + FilterType::Pointer genericFilter = FilterType::New(); + + genericFilter->SetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +}// end main + +//-------------------------------------------------------------------- diff --git a/tools/clitkInvertVF.ggo b/tools/clitkInvertVF.ggo new file mode 100644 index 0000000..da3ca8b --- /dev/null +++ b/tools/clitkInvertVF.ggo @@ -0,0 +1,17 @@ +#File clitkInvertVF.ggo +#Author: Jef Vandemeulebroucke +#Date : Tue 15 June 16.35 + +Package "clitk" +Version "Read a DVF and invert it using a linear splat to the target, or by subsumpling the input grid and matching it to the output grid" + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off +option "threads" - "Number of threads (default=min(8, #CPU))" int no + +option "input" i "Input VF filename" string yes +option "output" o "Output VF filename" string yes +option "type" t "Type of filter: 0=clitk (fast forward splat using linear kernels), 1= itk (grid subsumpling with controllable precision)" int no default="0" +option "threadSafe" - "Clitk: use thread safe algorithm" flag off +option "pad" p "Clitk: edge padding value (1 or N number of values!, defautls to zeros)" double multiple no +option "sampling" s "Itk: subsampling factor" int no default="20" diff --git a/tools/clitkInvertVFGenericFilter.cxx b/tools/clitkInvertVFGenericFilter.cxx new file mode 100644 index 0000000..47d7923 --- /dev/null +++ b/tools/clitkInvertVFGenericFilter.cxx @@ -0,0 +1,22 @@ +#ifndef clitkInvertVFGenericFilter_cxx +#define clitkInvertVFGenericFilter_cxx + +/* ================================================= + * @file clitkInvertVFGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkInvertVFGenericFilter.h" + + +namespace clitk +{ + + +} //end clitk + +#endif //#define clitkInvertVFGenericFilter_cxx diff --git a/tools/clitkInvertVFGenericFilter.h b/tools/clitkInvertVFGenericFilter.h new file mode 100644 index 0000000..6559843 --- /dev/null +++ b/tools/clitkInvertVFGenericFilter.h @@ -0,0 +1,99 @@ +#ifndef clitkInvertVFGenericFilter_h +#define clitkInvertVFGenericFilter_h + +/* ================================================= + * @file clitkInvertVFGenericFilter.h + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk include +#include "clitkIO.h" +#include "clitkCommon.h" +#include "clitkInvertVF_ggo.h" +#include "clitkInvertVFFilter.h" + +//itk include +#include "itkLightObject.h" +#include "itkInverseDeformationFieldImageFilter.h" + +namespace clitk +{ + + template + class ITK_EXPORT InvertVFGenericFilter : public itk::LightObject + { + public: + //---------------------------------------- + // ITK + //---------------------------------------- + typedef InvertVFGenericFilter Self; + typedef itk::LightObject Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( InvertVFGenericFilter, LightObject ); + + + //---------------------------------------- + // Typedefs + //---------------------------------------- + + + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetArgsInfo(const args_info_type & a) + { + m_ArgsInfo=a; + m_Verbose=m_ArgsInfo.verbose_flag; + m_InputFileName=m_ArgsInfo.input_arg; + } + + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(); + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + InvertVFGenericFilter(); + ~InvertVFGenericFilter() {}; + + + //---------------------------------------- + // Templated members + //---------------------------------------- + template void UpdateWithDim(std::string PixelType); + template void UpdateWithDimAndPixelType(); + + + //---------------------------------------- + // Data members + //---------------------------------------- + args_info_type m_ArgsInfo; + bool m_Verbose; + std::string m_InputFileName; + + }; + + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkInvertVFGenericFilter.txx" +#endif + +#endif // #define clitkInvertVFGenericFilter_h diff --git a/tools/clitkInvertVFGenericFilter.txx b/tools/clitkInvertVFGenericFilter.txx new file mode 100644 index 0000000..c2bcc27 --- /dev/null +++ b/tools/clitkInvertVFGenericFilter.txx @@ -0,0 +1,166 @@ +#ifndef clitkInvertVFGenericFilter_txx +#define clitkInvertVFGenericFilter_txx + +/* ================================================= + * @file clitkInvertVFGenericFilter.txx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +namespace clitk +{ + + //----------------------------------------------------------- + // Constructor + //----------------------------------------------------------- + template + InvertVFGenericFilter::InvertVFGenericFilter() + { + m_Verbose=false; + m_InputFileName=""; + } + + + //----------------------------------------------------------- + // Update + //----------------------------------------------------------- + template + void InvertVFGenericFilter::Update() + { + // Read the Dimension and PixelType + int Dimension; + std::string PixelType; + ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType); + + + // Call UpdateWithDim + if(Dimension==2) UpdateWithDim<2>(PixelType); + else if(Dimension==3) UpdateWithDim<3>(PixelType); + // else if (Dimension==4)UpdateWithDim<4>(PixelType); + else + { + std::cout<<"Error, Only for 2 or 3 Dimensions!!!"< + template + void + InvertVFGenericFilter::UpdateWithDim(std::string PixelType) + { + if (m_Verbose) std::cout << "Image was detected to be "<(); + // } + // else if(PixelType == "unsigned_short"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_short..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + + // else if (PixelType == "unsigned_char"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_char..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + + // else if (PixelType == "char"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed_char..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + // else { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and float..." << std::endl; + UpdateWithDimAndPixelType >(); + // } + } + + + //------------------------------------------------------------------- + // Update with the number of dimensions and the pixeltype + //------------------------------------------------------------------- + template + template + void + InvertVFGenericFilter::UpdateWithDimAndPixelType() + { + + // ImageTypes + typedef itk::Image InputImageType; + typedef itk::Image OutputImageType; + + // Read the input + typedef itk::ImageFileReader InputReaderType; + typename InputReaderType::Pointer reader = InputReaderType::New(); + reader->SetFileName( m_InputFileName); + reader->Update(); + typename InputImageType::Pointer input= reader->GetOutput(); + + // Filter + typename OutputImageType::Pointer output; + switch (m_ArgsInfo.type_arg) + { + + // clitk filter + case 0: + { + // Create the InvertVFFilter + typedef clitk::InvertVFFilter FilterType; + typename FilterType::Pointer filter =FilterType::New(); + filter->SetInput(input); + filter->SetVerbose(m_Verbose); + if (m_ArgsInfo.threads_given) filter->SetNumberOfThreads(m_ArgsInfo.threads_arg); + if (m_ArgsInfo.pad_given) + { + PixelType pad; + if (m_ArgsInfo.pad_given != (pad.GetNumberOfComponents()) ) + pad.Fill(m_ArgsInfo.pad_arg[0]); + else + for(unsigned int i=0; iSetThreadSafe(m_ArgsInfo.threadSafe_flag); + filter->Update(); + output=filter->GetOutput(); + + break; + } + + case 1: + { + // Create the InverseDeformationFieldFilter + typedef itk::InverseDeformationFieldImageFilter FilterType; + typename FilterType::Pointer filter =FilterType::New(); + filter->SetInput(input); + filter->SetOutputOrigin(input->GetOrigin()); + filter->SetOutputSpacing(input->GetSpacing()); + filter->SetSize(input->GetLargestPossibleRegion().GetSize()); + filter->SetSubsamplingFactor(m_ArgsInfo.sampling_arg); + filter->Update(); + output=filter->GetOutput(); + + break; + } + + } + + // Output + typedef itk::ImageFileWriter WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(m_ArgsInfo.output_arg); + writer->SetInput(output); + writer->Update(); + + } + + +}//end clitk + +#endif //#define clitkInvertVFGenericFilter_txx diff --git a/tools/clitkRigidRegistration.cxx b/tools/clitkRigidRegistration.cxx new file mode 100644 index 0000000..9bad7d1 --- /dev/null +++ b/tools/clitkRigidRegistration.cxx @@ -0,0 +1,110 @@ +/*------------------------------------------------------------------------- + + Program: clitk + Module: $RCSfile: clitkRigidRegistration.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +-------------------------------------------------------------------------*/ + +/** + ------------------------------------------------- + * @file clitkRigidRegistration.cxx + * @author Jef Vandemeulebroucke + * @date 14 August 2007 + * + * @brief Perform a rigid registration between 2 images + * + -------------------------------------------------*/ + + +// clitk include +#include "clitkIO.h" +#include "clitkImageCommon.h" +#include "clitkRigidRegistration_ggo.h" +#include "clitkRigidRegistrationGenericFilter.h" + +using namespace clitk; +using namespace std; + + +int main( int argc, char *argv[] ) +{ + //init command line and check options + GGO(args_info); + CLITK_INIT; + + //--------------------------------------------------------------------------- + //Set all the options passed through the commandline + + RigidRegistrationGenericFilter rigidRegistration; + + rigidRegistration.SetVerbose(args_info.verbose_flag); + rigidRegistration.SetGradient(args_info.gradient_flag); + rigidRegistration.SetZeroOrigin(args_info.zero_origin_flag); + + //Input + rigidRegistration.SetFixedImageName(args_info.reference_arg); + rigidRegistration.SetMovingImageName(args_info.object_arg); + rigidRegistration.SetFixedImageMaskGiven(args_info.mask_given); + if (args_info.mask_given) rigidRegistration.SetFixedImageMaskName(args_info.mask_arg); + + //Output + rigidRegistration.SetOutputGiven(args_info.output_given); + if (args_info.output_given) rigidRegistration.SetOutputName(args_info.output_arg); + rigidRegistration.SetCheckerAfterGiven(args_info.checker_after_given); + if (args_info.checker_after_given) rigidRegistration.SetCheckerAfterName(args_info.checker_after_arg); + rigidRegistration.SetCheckerBeforeGiven(args_info.checker_before_given); + if (args_info.checker_before_given) rigidRegistration.SetCheckerBeforeName(args_info.checker_before_arg); + rigidRegistration.SetBeforeGiven(args_info.before_given); + if (args_info.before_given) rigidRegistration.SetBeforeName(args_info.before_arg); + rigidRegistration.SetAfterGiven(args_info.after_given); + if (args_info.after_given) rigidRegistration.SetAfterName(args_info.after_arg); + rigidRegistration.SetMatrixGiven(args_info.matrix_given); + if (args_info.matrix_given) rigidRegistration.SetMatrixName(args_info.matrix_arg); + + //Interp + rigidRegistration.SetInterpType(args_info.interp_arg); + + //Transform + rigidRegistration.SetRotX(args_info.rotX_arg); + rigidRegistration.SetRotY(args_info.rotY_arg); + rigidRegistration.SetRotZ(args_info.rotZ_arg); + rigidRegistration.SetTransX(args_info.transX_arg); + rigidRegistration.SetTransY(args_info.transY_arg); + rigidRegistration.SetTransZ(args_info.transZ_arg); + + //Optimizer + rigidRegistration.SetLevels(args_info.levels_arg); + rigidRegistration.SetIstep(args_info.Istep_arg); + rigidRegistration.SetFstep(args_info.Fstep_arg); + rigidRegistration.SetRelax(args_info.relax_arg); + rigidRegistration.SetInc(args_info.inc_arg); + rigidRegistration.SetDec(args_info.dec_arg); + rigidRegistration.SetIter(args_info.iter_arg); + rigidRegistration.SetRweight(args_info.Rweight_arg); + rigidRegistration.SetTweight(args_info.Tweight_arg); + + //Metric + rigidRegistration.SetMetricType(args_info.metric_arg); + rigidRegistration.SetSamples(args_info.samples_arg); + rigidRegistration.SetBins(args_info.bins_arg); + rigidRegistration.SetRandom(args_info.random_flag); + rigidRegistration.SetStdDev(args_info.stdDev_arg); + + //Preprocessing + rigidRegistration.SetBlur(args_info.blur_arg); + rigidRegistration.SetNormalize(args_info.normalize_flag); + + rigidRegistration.Update(); + +} diff --git a/tools/clitkRigidRegistration.ggo b/tools/clitkRigidRegistration.ggo new file mode 100644 index 0000000..5002e60 --- /dev/null +++ b/tools/clitkRigidRegistration.ggo @@ -0,0 +1,55 @@ +# file clitkRigidRegistration.ggo +Package "clitkRigidRegistration" +version "1.0" +purpose "Compute a rigid registration between two images." + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off +option "gradient" - "If verbose, show gradient at each iteration" flag off + +section "Input (Both images have to be of the same dimension (2 or 3D). For 2D-3D registrations, give the 2D image a third dimension of 1 and set it to the reference image.)" +option "reference" i "Reference or fixed image filename" string yes +option "object" j "Object or moving image filename" string yes +option "mask" m "Mask to placed over the reference image" string no + +section "Output" +option "output" o "Transformed object image filename" string no +option "checker_after" - "Checherboard representation of the transformed object image and reference image" string no +option "checker_before" - "Checherboard representation of the object image and reference image" string no +option "after" - "Difference between the reference image and the transformed object" string no +option "before" - "Difference between the reference image and the original object image" string no +option "matrix" - "Affine matrix (reference to object space) filename " string no + +section "Interpolator" +option "interp" - "Interpolator used during registration: 0=nearestneighbor, 1=linear, 2=bspline" int no default="1" + +section "Transform (Input and Output transformation parameters map the physical space of the fixed or reference image into the physical space of the moving or object image. Positive rotations result in a counter-clockwise rotation for the moving image. Positive translations result in shift along the negative axis for the moving image.)" +option "transX" x "Initial translation in mm along the X axis" float no default="0.0" +option "transY" y "Initial translation in mm along the Y axis" float no default="0.0" +option "transZ" z "Initial translation in mm along the Z axis" float no default="0.0" +option "rotX" X "Initial rotation in rad along the X axis" float no default="0.0" +option "rotY" Y "Initial rotation in rad along the Y axis" float no default="0.0" +option "rotZ" Z "Initial rotation in rad along the Z axis" float no default="0.0" + +section "Optimizer" +option "levels" l "Number of multiresolution levels" int no default="1" +option "Istep" - "Initial stepsize in mm in the first level(to be multiplied with the gradient)" float no default="2.0" +option "Fstep" - "Final stepsize in mm in the first level (to be multiplied with the gradient)" float no default="0.1" +option "relax" - "Relaxation of the stepsize (multiplied each time the gradient changes sign)" float no default="0.7" +option "inc" - "Increment factor x previous stepsize = new stepsize when going to next level" float no default="1.2" +option "dec" - "Decrement factor(:) previous stepsize = new final stepsize when going to next level" float no default="4.0" +option "iter" - "Maximum number of iterations at each level" int no default="200" +option "Rweight" - "Weight of 1° of rotation during optimisation (high weight, less change)" float no default="50.0" +option "Tweight" - "Weight of 1mm of translation during optimisation (high weight, less change)" float no default="1.0" + +section "Metric (Use a high fraction of samples for detailed images (eg. 0.2, 0.5). For smooth images 0.01 might be enough. Use enough bins to cover the dynamique range. Randomizing the samples will make each execution different.)" +option "metric" - "Metric used during registration: 0=MS, 1=MI, 2=Mattes' MI, 3=CR" int no default="0" +option "samples" - "If using MI or Mattes' MI, specify fraction [0, 1] of samples of the reference image" float no default="0.2" +option "bins" - "If using Mattes' MI, specify the number of histogram bins for the PDF estimation of the reference image" int no default="50" +option "random" - "If using Mattes' MI and MI, specify if the set of samples should be taken randomly" flag off +option "stdDev" - "If using MI, specify the standard deviation in mm of the gaussian kernels for both PDF estimations" float no default="0.4" + +section "Preprocessing" +option "normalize" - "Normalize images before registration (not necessary for Mattes' MI)" flag off +option "blur" - "Blur images before registration, use Gaussian with std dev (none by default) " float no default="0.0" +option "zero_origin" - "Reset the input images' origins to zero, to avoid additional shifts according to jef" flag off diff --git a/tools/clitkSetBackground.cxx b/tools/clitkSetBackground.cxx new file mode 100644 index 0000000..3d6ddc8 --- /dev/null +++ b/tools/clitkSetBackground.cxx @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + ------------------------------------------------------------------------*/ + +/* ================================================= + * @file clitkSetBackground.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk +#include "clitkSetBackground_ggo.h" +#include "clitkIO.h" +#include "clitkSetBackgroundGenericFilter.h" + + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkSetBackground,args_info); + CLITK_INIT; + + // Filter + clitk::SetBackgroundGenericFilter::Pointer genericFilter=clitk::SetBackgroundGenericFilter::New(); + + genericFilter->SetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +}// end main + +//-------------------------------------------------------------------- diff --git a/tools/clitkSetBackground.ggo b/tools/clitkSetBackground.ggo new file mode 100644 index 0000000..c69413b --- /dev/null +++ b/tools/clitkSetBackground.ggo @@ -0,0 +1,14 @@ +#File clitkSetBackground.ggo +Package "clitkSetBackground" +version "1.0" +purpose "" + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off + +option "input" i "Input image filename" string yes +option "output" o "Output image filename" string yes +option "mask" m "Mask image filename" string yes +option "outsideValue" p "Outside value" double no default="0.0" +option "maskValue" l "Mask value" double no default="0.0" +option "fg" - "Foreground mode" flag off diff --git a/tools/clitkSetBackgroundGenericFilter.cxx b/tools/clitkSetBackgroundGenericFilter.cxx new file mode 100644 index 0000000..6c007a0 --- /dev/null +++ b/tools/clitkSetBackgroundGenericFilter.cxx @@ -0,0 +1,55 @@ +#ifndef clitkSetBackgroundGenericFilter_cxx +#define clitkSetBackgroundGenericFilter_cxx + +/* ================================================= + * @file clitkSetBackgroundGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkSetBackgroundGenericFilter.h" + + +namespace clitk +{ + + + //----------------------------------------------------------- + // Constructor + //----------------------------------------------------------- + SetBackgroundGenericFilter::SetBackgroundGenericFilter() + { + m_Verbose=false; + m_InputFileName=""; + } + + + //----------------------------------------------------------- + // Update + //----------------------------------------------------------- + void SetBackgroundGenericFilter::Update() + { + // Read the Dimension and PixelType + int Dimension; + std::string PixelType; + ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType); + + + // Call UpdateWithDim + if(Dimension==2) UpdateWithDim<2>(PixelType); + else if(Dimension==3) UpdateWithDim<3>(PixelType); + else if (Dimension==4)UpdateWithDim<4>(PixelType); + else + { + std::cout<<"Error, Only for 2 , 3 or 4 Dimensions!!!"< Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( SetBackgroundGenericFilter, LightObject ); + + + //---------------------------------------- + // Typedefs + //---------------------------------------- + + + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetArgsInfo(const gengetopt_args_info_clitkSetBackground & a) + { + m_ArgsInfo=a; + m_Verbose=m_ArgsInfo.verbose_flag; + m_InputFileName=m_ArgsInfo.input_arg; + } + + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(); + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + SetBackgroundGenericFilter(); + ~SetBackgroundGenericFilter() {}; + + + //---------------------------------------- + // Templated members + //---------------------------------------- + template void UpdateWithDim(std::string PixelType); + template void UpdateWithDimAndPixelType(); + + + //---------------------------------------- + // Data members + //---------------------------------------- + gengetopt_args_info_clitkSetBackground m_ArgsInfo; + bool m_Verbose; + std::string m_InputFileName; + + }; + + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkSetBackgroundGenericFilter.txx" +#endif + +#endif // #define clitkSetBackgroundGenericFilter_h diff --git a/tools/clitkSetBackgroundGenericFilter.txx b/tools/clitkSetBackgroundGenericFilter.txx new file mode 100644 index 0000000..16cdfa5 --- /dev/null +++ b/tools/clitkSetBackgroundGenericFilter.txx @@ -0,0 +1,98 @@ +#ifndef clitkSetBackgroundGenericFilter_txx +#define clitkSetBackgroundGenericFilter_txx + +/* ================================================= + * @file clitkSetBackgroundGenericFilter.txx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +namespace clitk +{ + + //------------------------------------------------------------------- + // Update with the number of dimensions + //------------------------------------------------------------------- + template + void + SetBackgroundGenericFilter::UpdateWithDim(std::string PixelType) + { + if (m_Verbose) std::cout << "Image was detected to be "<(); + } + // else if(PixelType == "unsigned_short"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_short..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + + else if (PixelType == "unsigned_char"){ + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_char..." << std::endl; + UpdateWithDimAndPixelType(); + } + + // else if (PixelType == "char"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed_char..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + else { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and float..." << std::endl; + UpdateWithDimAndPixelType(); + } + } + + + //------------------------------------------------------------------- + // Update with the number of dimensions and the pixeltype + //------------------------------------------------------------------- + template + void + SetBackgroundGenericFilter::UpdateWithDimAndPixelType() + { + + // ImageTypes + typedef itk::Image InputImageType; + typedef itk::Image MaskImageType; + + // Read the input + typedef itk::ImageFileReader InputReaderType; + typename InputReaderType::Pointer reader = InputReaderType::New(); + reader->SetFileName( m_InputFileName); + typename InputImageType::Pointer input= reader->GetOutput(); + + // Read the mask + typedef itk::ImageFileReader MaskReaderType; + typename MaskReaderType::Pointer maskReader = MaskReaderType::New(); + maskReader->SetFileName( m_ArgsInfo.mask_arg); + typename MaskImageType::Pointer mask= maskReader->GetOutput(); + + // Filter setting background + typedef clitk::SetBackgroundImageFilter SetBackgroundFilterType; + typename SetBackgroundFilterType::Pointer setBackgroundFilter = SetBackgroundFilterType::New(); + setBackgroundFilter->SetInput(input); + setBackgroundFilter->SetInput2(mask); + if(m_ArgsInfo.fg_flag) setBackgroundFilter->SetForeground(m_ArgsInfo.fg_flag); + if(m_ArgsInfo.maskValue_given) setBackgroundFilter->SetMaskValue(m_ArgsInfo.maskValue_arg); + if(m_ArgsInfo.outsideValue_given) setBackgroundFilter->SetOutsideValue(m_ArgsInfo.outsideValue_arg); + setBackgroundFilter->Update(); + typename InputImageType::Pointer output =setBackgroundFilter->GetOutput(); + + // Output + typedef itk::ImageFileWriter WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(m_ArgsInfo.output_arg); + writer->SetInput(output); + writer->Update(); + + } + + +}//end clitk + +#endif //#define clitkSetBackgroundGenericFilter_txx diff --git a/tools/clitkSignalFilter.cxx b/tools/clitkSignalFilter.cxx new file mode 100644 index 0000000..fad1021 --- /dev/null +++ b/tools/clitkSignalFilter.cxx @@ -0,0 +1,83 @@ +/*========================================================================= + + Program: clitk + Module: $RCSfile: clitkSignalFilter.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:56 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef CLITKSIGNALFILTER_CXX +#define CLITKSIGNALFILTER_CXX +/** + ================================================= + * @file clitkSignalFilter.cxx + * @author Jef Vandemeulebroucke + * @date 23 April 2008 + * + * @brief "Apply a filter to the signal" + =================================================*/ + +// clitk include +#include "clitkSignalFilter_ggo.h" +#include "clitkSignal.h" +#include "clitkIO.h" +#include "clitkIOCommon.h" + +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkSignalFilter, args_info); + CLITK_INIT; + + //input + clitk::Signal input; + input.Read (args_info.input_arg); + clitk::Signal input2; + if (args_info.input2_given) input2.Read(args_info.input2_arg); + + double p1 = args_info.p1_arg; + double p2 = args_info.p2_arg; + + //process + + if( args_info.multiply_flag) input*=input2; + if( args_info.divide_flag) input/=input2; + if( args_info.norm_flag) input=input.Normalize (p1, p2); + if( args_info.highPass_flag) input=input.HighPassFilter(p1,p2); + if( args_info.lowPass_flag) input=input.LowPassFilter(p1,p2); + if( args_info.detect_flag) input=input.DetectLocalExtrema(static_cast(p1)); + if( args_info.limPhase_flag) input=input.LimPhase(); + if( args_info.monPhase_flag) input=input.MonPhase(); + if( args_info.monPhaseDE_flag) input=input.MonPhaseDE(p1,p2); + if( args_info.average_flag) input=input.MovingAverageFilter(static_cast (p1)); + if( args_info.ssd_flag) std::cout<<"The sqrt of the mean SSD is "<< input.SSD(input2)<(p1),static_cast(p2)); + if( args_info.limit_flag) input=input.LimitSignalRange(); +// if( args_info._flag) input=input; +// if( args_info._flag) input=input; +// if( args_info._flag) input=input; +// if( args_info._flag) input=input; + // if( args_info._flag) input=input; + // if( args_info._flag) input=input; + // if( args_info._flag) input=input; + + if (args_info.output_given) input.Write(args_info.output_arg); + + return EXIT_SUCCESS; + +} + +#endif diff --git a/tools/clitkSignalFilter.ggo b/tools/clitkSignalFilter.ggo new file mode 100644 index 0000000..5067fcd --- /dev/null +++ b/tools/clitkSignalFilter.ggo @@ -0,0 +1,27 @@ +#File clitkSignalFilter.ggo +Package "clitk" +Version "Pass an filter on an signal" + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off +option "input" i "Input grid filename" string yes +option "input2" j "Second Input grid filename" string no +option "p1" - "p1" double no +option "p2" - "p2" double no +option "output" o "Output grid filename" string no +option "multiply" - "Mulitply values of input 1 with input 2 (same size)" flag off +option "divide" - "Divide values of input 1 with input 2 (same size, zeros are skipped)" flag off +option "norm" n "Normalize signal between p1=min and p2=max" flag off +option "rescale" - "Rescale signal to p1=mean and p2=StdDev" flag off +option "highPass" - "High Pass Filter: p1=sampPeriod, p2= cutOffFrequecy" flag off +option "lowPass" - "Low Pass Filter: p1=sampPeriod, p2= cutOffFrequecy" flag off +option "detect" - "Detect Local extrema: local window= 2*p1+1, p1>=1" flag off +option "limPhase" - "Convert extrema signal into limited phase [0, 1[" flag off +option "monPhase" - "Convert extrema signal into monotone phase [0, inf[" flag off +option "monPhaseDE" - "Convert extrema signal into scattered monotone phase, taking into account both extrema (p1=eEPhaseValue,p2=eIPhaseValue)" flag off +option "average" - "Moving Average filter: window= 2*p1+1 [0, inf[" flag off +option "ssd" - "Calculate the sqrt of the mean SSD between i and j" flag off +option "gauss" - "Pass a small gauss-like kernel (121-mask)" flag off +option "interp" - "Linearly interpolate scattered values (unknow values=-1)" flag off +option "approx" - "Bspline approximate scattered values(unknow values=-1, p1=Order, p2=number of control points" flag off +option "limit" - "Limit the range to [0, 1[ (signal-floor (signal))" flag off diff --git a/tools/clitkSignalMeanPositionFilter.cxx b/tools/clitkSignalMeanPositionFilter.cxx new file mode 100644 index 0000000..8eaa34c --- /dev/null +++ b/tools/clitkSignalMeanPositionFilter.cxx @@ -0,0 +1,222 @@ +/*========================================================================= + + Program: clitk + Module: $RCSfile: clitkSignalMeanPositionFilter.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "clitkSignalMeanPositionFilter.h" + +//--------------------------------------------------------------------- +void clitk::SignalMeanPositionFilter::SetParameters(gengetopt_args_info_clitkSignalMeanPositionTracking & args) { + args_info = args; + mEtaIsSet = false; + mOutputFilenameIsSet = false; + mOutputResidualFilenameIsSet = false; + mInput.Read(args_info.input_arg); + mAugmentationDelay = args_info.delay_arg; + mIsAdaptiveMethod = false; + mWindowLength = -1; + if (args_info.eta_given) { + mEta = args_info.eta_arg; + mEtaIsSet = true; + } + mMaxIteration = args_info.iter_arg; + if (args_info.output_given) { + mOutputFilenameIsSet = true; + mOutputFilename = args_info.output_arg; + } + if (args_info.residual_given) { + mOutputResidualFilenameIsSet = true; + mOutputResidualFilename = args_info.residual_arg; + } + if (args_info.augmented_given) { + mOutputAugmentedFilenameIsSet = true; + mOutputAugmentedFilename = args_info.augmented_arg; + } + mVerbose = args_info.verbose_flag; + mVerboseIteration = args_info.verbose_iteration_flag; + if (args_info.L_given) { + mIsAdaptiveMethod = true; + mWindowLength = args_info.L_arg; + } +} +//--------------------------------------------------------------------- + + +//--------------------------------------------------------------------- +void clitk::SignalMeanPositionFilter::Update() { + + // DEBUG +// int e = 5; +// clitk::Signal temp; +// temp.resize(mInput.size()*e); +// for(unsigned int i=0; i Vector2d; + + void SetParameters(gengetopt_args_info_clitkSignalMeanPositionTracking & args_info); + void Update(); + + protected: + gengetopt_args_info_clitkSignalMeanPositionTracking args_info; + clitk::Signal mInput; + clitk::Signal mAugmentedInputX; + clitk::Signal mAugmentedInputY; + int mAugmentationDelay; + int mMaxIteration; + double mEta; + bool mEtaIsSet; + bool mOutputFilenameIsSet; + bool mOutputResidualFilenameIsSet; + bool mOutputAugmentedFilenameIsSet; + std::string mOutputFilename; + std::string mOutputResidualFilename; + std::string mOutputAugmentedFilename; + bool mVerbose; + bool mVerboseIteration; + bool mIsAdaptiveMethod; + std::vector mCurrentResidual; + int mWindowLength; + std::vector mCenters; + + void FitEllipse(clitk::Ellipse & An); + void AdaptiveFitEllipse(clitk::Ellipse & An); + + void ComputeAugmentedSpace(const clitk::Signal & input, + clitk::Signal & outputX, + clitk::Signal & outputY, + unsigned int delay); + }; + //--------------------------------------------------------------------- + +} // end namespace + +#endif diff --git a/tools/clitkSignalMeanPositionTracking.cxx b/tools/clitkSignalMeanPositionTracking.cxx new file mode 100644 index 0000000..2b64fa4 --- /dev/null +++ b/tools/clitkSignalMeanPositionTracking.cxx @@ -0,0 +1,53 @@ +/*========================================================================= + + Program: clitk + Module: $RCSfile: clitkSignalMeanPositionTracking.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:56 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef CLITKSIGNALMEANPOSITIONTRACKING_CXX +#define CLITKSIGNALMEANPOSITIONTRACKING_CXX +/** + ================================================= + * @file clitkSignalMeanPositionTracking.cxx + * @author David Sarrut + * @date Sept 2009 + * + * @brief "See Ruan 2007, compute mean position from a signal" + =================================================*/ + +// clitk include +#include "clitkSignalMeanPositionTracking_ggo.h" +#include "clitkSignalMeanPositionFilter.h" +#include "clitkIO.h" +#include "clitkIOCommon.h" + +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkSignalMeanPositionTracking,args_info); + CLITK_INIT; + + // Init filter + clitk::SignalMeanPositionFilter filter; + filter.SetParameters(args_info); + + // Run + filter.Update(); + + // This is the end my friend + return EXIT_SUCCESS; +} + +#endif diff --git a/tools/clitkSignalMeanPositionTracking.ggo b/tools/clitkSignalMeanPositionTracking.ggo new file mode 100644 index 0000000..46baa88 --- /dev/null +++ b/tools/clitkSignalMeanPositionTracking.ggo @@ -0,0 +1,22 @@ +#File clitkSignalMeanPositionTracking.ggo +Package "clitkSignalMeanPositionTracking" +version "1.0" +purpose "See Ruan 2008, compute mean position from a signal" + +option "config" - "Config file" string no +option "input" i "Input signal filename" string yes +option "delay" d "Delay for augmented space" int no default="10" +option "eta" e "Convergence param (auto if not given)" double no +option "iter" - "Max # of iterations" int no default="100" +option "L" L "Sliding window length" int no +option "t" t "DEBUG" int no + +section "Output" +option "output" o "Output ellipse param filename (2 lines=initial/final ; 6 quadratic param + 5 parametric param=center/axis/theta)" string no +option "residual" r "Output optimisation residual filemane" string no +option "augmented" a "Output augmented signal filemane" string no + +section "Verbose" +option "verbose" v "Verbose" flag off +option "verbose_iteration" - "Verbose each iteration" flag off + diff --git a/tools/clitkSplitImage.cxx b/tools/clitkSplitImage.cxx new file mode 100644 index 0000000..8a935e0 --- /dev/null +++ b/tools/clitkSplitImage.cxx @@ -0,0 +1,51 @@ +/*------------------------------------------------------------------------= + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + ------------------------------------------------------------------------=*/ + +/** + ------------------------------------------------= + * @file clitkSplitImage.cxx + * @author Joël Schaerer + * @date 20 April 2009 + ------------------------------------------------=*/ + +// clitk include +#include "clitkSplitImage_ggo.h" +#include "clitkSplitImageGenericFilter.h" +#include "clitkIO.h" + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkSplitImage, args_info); + CLITK_INIT; + + // Read image dimension + itk::ImageIOBase::Pointer header = clitk::readImageHeader(args_info.input_arg); + unsigned int dim = header->GetNumberOfDimensions(); + + // Check parameters + if (args_info.dimension_given >= dim) { + std::cerr << "ERROR : image has " << dim << "dimensions, split dimension should be between 0 and " << dim-1 << "." << std::endl; + exit(-1); + } + // Main filter + clitk::SplitImageGenericFilter filter; + filter.SetInputFilename(args_info.input_arg); + filter.SetOutputFilename(args_info.output_arg); + filter.SetSplitDimension(args_info.dimension_arg); + filter.SetVerbose(args_info.verbose_flag); + filter.Update(); + + // this is the end my friend + return 0; +} // end main diff --git a/tools/clitkSplitImage.ggo b/tools/clitkSplitImage.ggo new file mode 100644 index 0000000..03d77d8 --- /dev/null +++ b/tools/clitkSplitImage.ggo @@ -0,0 +1,12 @@ +#File clitkSplitImage.ggo +Package "clitkSplitImage" +version "1.0" +purpose "Split an image into n images along a dimension" + + +option "config" - "Config file" string no +option "input" i "Input image filename" string yes +option "output" o "Output image base filename" string yes +option "verbose" v "Verbose" flag off + +option "dimension" d "Dimension to split on" int yes diff --git a/tools/clitkVFMerge.cxx b/tools/clitkVFMerge.cxx new file mode 100644 index 0000000..fa0a75e --- /dev/null +++ b/tools/clitkVFMerge.cxx @@ -0,0 +1,135 @@ +#ifndef CLITKVFMERGE_CXX +#define CLITKVFMERGE_CXX + +/** + * @file clitkVFMerge.cxx + * @author Jef Vandemeulebroucke + * @date June 15 10:14:53 2007 + * + * @brief Read in one VF (ex mhd, vf) and write to another. Transforming from mm to voxels needed for the vf format is implemented in clitkVfImageIO.cxx . + * + * + */ + +// clitk include +#include "clitkVFMerge_ggo.h" +#include "clitkIO.h" +#include "clitkIOCommon.h" + +// itk include +//#include "itkReadTransform.h" +#include "itkImageFileWriter.h" +#include +#include "itkImageFileReader.h" +//#include "itkRawImageIO.h" +//#include "macro.h" + +int main( int argc, char *argv[] ) +{ + + // Init command line + GGO(clitkVFMerge, args_info); + CLITK_INIT; + +const unsigned int SpaceDimension = 3; +const unsigned int ModelDimension = 4; +typedef itk::Vector< float, SpaceDimension > Displacement; +typedef itk::Image< Displacement, SpaceDimension > DeformationFieldType; +typedef itk::Image< Displacement, ModelDimension > DynamicDeformationFieldType; +typedef itk::ImageFileReader< DeformationFieldType > DeformationFieldReaderType; +typedef itk::ImageFileWriter< DynamicDeformationFieldType > DynamicDeformationFieldWriterType; + + +//declare the dynamic + DynamicDeformationFieldType::Pointer dynamicDeformationField=DynamicDeformationFieldType::New(); + + + //declare their iterators + typedef itk::ImageRegionIterator< DynamicDeformationFieldType> DynamicDeformationFieldIteratorType; + DynamicDeformationFieldIteratorType *dynamicIteratorPointer= new DynamicDeformationFieldIteratorType; + + for (unsigned int i=0 ; i< args_info.inputs_num ; i ++) + { + //read in the deformation field i + DeformationFieldReaderType::Pointer deformationFieldReader = DeformationFieldReaderType::New(); + deformationFieldReader->SetFileName( args_info.inputs[i]); + if (args_info.verbose_flag) std::cout<<"Reading VF number "<< i+1 << std::endl; + deformationFieldReader->Update(); + DeformationFieldType::Pointer currentDeformationField = deformationFieldReader->GetOutput(); + + //create an iterator for the current deformation field + typedef itk::ImageRegionIterator FieldIteratorType; + FieldIteratorType fieldIterator(currentDeformationField, currentDeformationField->GetLargestPossibleRegion()); + + //Allocate memory for the dynamic components + if (i==0) + { + DynamicDeformationFieldType::RegionType dynamicDeformationFieldRegion; + DynamicDeformationFieldType::RegionType::SizeType dynamicDeformationFieldSize; + DeformationFieldType::RegionType::SizeType deformationFieldSize; + deformationFieldSize= currentDeformationField->GetLargestPossibleRegion().GetSize(); + dynamicDeformationFieldSize[0]=deformationFieldSize[0]; + dynamicDeformationFieldSize[1]=deformationFieldSize[1]; + dynamicDeformationFieldSize[2]=deformationFieldSize[2]; + dynamicDeformationFieldSize[3]=args_info.inputs_num; + dynamicDeformationFieldRegion.SetSize(dynamicDeformationFieldSize); + DynamicDeformationFieldType::IndexType start; + start.Fill(0); + dynamicDeformationFieldRegion.SetIndex(start); + dynamicDeformationField->SetRegions(dynamicDeformationFieldRegion); + dynamicDeformationField->Allocate(); + + + //Set the spacing + DeformationFieldType::SpacingType spacing= currentDeformationField->GetSpacing(); + DynamicDeformationFieldType::SpacingType dynamicSpacing; + dynamicSpacing[0]=spacing[0]; + dynamicSpacing[1]=spacing[1]; + dynamicSpacing[2]=spacing[2]; + dynamicSpacing[3]=args_info.spacing_arg; //JV par exemple + dynamicDeformationField->SetSpacing(dynamicSpacing); + DynamicDeformationFieldType::PointType origin; + origin[0]=args_info.xorigin_arg; + origin[1]=args_info.yorigin_arg; + origin[2]=args_info.zorigin_arg; + origin[3]=0; //temporal origin is always 0 + dynamicDeformationField->SetOrigin(origin); + + // Creating iterators for the currentDeformationField and the DynamicDeformationField + DynamicDeformationFieldIteratorType *dynamicIterator= new DynamicDeformationFieldIteratorType(dynamicDeformationField, dynamicDeformationField->GetLargestPossibleRegion()); + dynamicIteratorPointer=dynamicIterator; + dynamicIteratorPointer->GoToBegin(); + } + if (args_info.verbose_flag) std::cout<<"Merging VF number "<< i+1 << std::endl; + //Copy the current component of the input into dynamicDeformationFieldComponent + fieldIterator.GoToBegin(); + while(!fieldIterator.IsAtEnd()) + { + dynamicIteratorPointer->Set(fieldIterator.Get()); + ++fieldIterator; + ++(*dynamicIteratorPointer); + } + } + + +//Write the vector field + DynamicDeformationFieldWriterType::Pointer writer = DynamicDeformationFieldWriterType::New(); + writer->SetInput( dynamicDeformationField ); + writer->SetFileName( args_info.output_arg ); + if (args_info.verbose_flag) std::cout<<"Writing the dynamic VF"<< std::endl; + + + try { + + writer->Update( ); + } + catch( itk::ExceptionObject & excp ) { + std::cerr << "Problem writing the output file" << std::endl; + std::cerr << excp << std::endl; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} +#endif + + diff --git a/tools/clitkVFMerge.ggo b/tools/clitkVFMerge.ggo new file mode 100644 index 0000000..0b073c7 --- /dev/null +++ b/tools/clitkVFMerge.ggo @@ -0,0 +1,14 @@ +#File clitkVFMerge.ggo +#Author: Jef Vandemeulebroucke +#Date : Tue 15 June 16.35 + +Package "clitk" +Version "Read a bunch of vector fields (.mhd, .vf, ..) and turn them into a higher dimension vector field (.mhd, ...)" + +option "config" - "Config file" string no +option "output" o "Output VF filename" string yes +option "spacing" s "Spacing for the fourth dimension" float no default="1" +option "verbose" v "Verbose" flag off +option "xorigin" x "Set the x origin of the output vf" float default="0." +option "yorigin" y "Set the y origin of the output vf" float default="0." +option "zorigin" z "Set the z origin of the output vf" float default="0." diff --git a/tools/clitkVFResample.cxx b/tools/clitkVFResample.cxx new file mode 100644 index 0000000..e9605e1 --- /dev/null +++ b/tools/clitkVFResample.cxx @@ -0,0 +1,163 @@ +/*------------------------------------------------------------------------- + +Program: clitk +Module: $RCSfile: clitkVFResample.cxx,v $ +Language: C++ +Date: $Date: 2010/01/06 13:31:56 $ +Version: $Revision: 1.1 $ + +Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de +l'Image). All rights reserved. See Doc/License.txt or +http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +-------------------------------------------------------------------------*/ + +#ifndef CLITKVFRESAMPLE_CXX +#define CLITKVFRESAMPLE_CXX + +/** + ------------------------------------------------= + * @file clitkImageResample.cxx + * @author David Sarrut + * @date 23 Feb 2008 08:37:53 + ------------------------------------------------=*/ + +// clitk +#include "clitkImageResample_ggo.h" +#include "clitkIO.h" +#include "clitkVFResampleGenericFilter.h" + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkImageResample, args_info); + CLITK_INIT; + + // Read input image header to check image dimension + itk::ImageIOBase::Pointer header = clitk::readImageHeader(args_info.input_arg); + unsigned int dim = header->GetNumberOfDimensions(); + std::string pixelTypeName = header->GetComponentTypeAsString(header->GetComponentType()); + + // Print image info if verbose + if (args_info.verbose_flag) { + std::cout << "Input image <" << args_info.input_arg << "> is "; + clitk::printImageHeader(header, std::cout); + std::cout << std::endl; + } + + // Get input size/spacing + std::vector inputSize; + std::vector inputSpacing; + inputSize.resize(dim); + inputSpacing.resize(dim); + for(unsigned int i=0; iGetSpacing(i); + inputSize[i] = header->GetDimensions(i); + } + + // Get options + std::vector outputSize; + std::vector outputSpacing; + outputSize.resize(dim); + outputSpacing.resize(dim); + + // Check options + if (!args_info.size_given && !args_info.spacing_given) { + std::cerr << "Please indicate output size or spacing." << std::endl; + exit(0); + } + + // Check options + if (args_info.size_given && args_info.spacing_given) { + std::cerr << "Please indicate only output size or spacing, not both." << std::endl; + exit(0); + } + + // Size is given and not spacing + if (args_info.size_given && !args_info.spacing_given) { + if (args_info.size_given != dim) { + std::cerr << "Input image is " << dim << "D, please give " << dim << " size numbers." << std::endl; + exit(0); + } + for(unsigned int i=0; i sigma; + sigma.resize(args_info.gauss_given); + std::copy(args_info.gauss_arg, args_info.gauss_arg+args_info.gauss_given, sigma.begin()); + if (args_info.gauss_given) { + if (args_info.gauss_given != dim) { + if (args_info.gauss_given == 1) { + sigma.resize(dim); + for(unsigned int i=0; iSetInputFilename(args_info.input_arg); + filter->SetOutputSize(outputSize); + filter->SetOutputSpacing(outputSpacing); + filter->SetInterpolationName(args_info.interp_arg); + filter->SetBSplineOrder(args_info.order_arg); + filter->SetBLUTSampling(args_info.sampling_arg); + if (args_info.gauss_given) + filter->SetGaussianSigma(sigma); + filter->SetOutputFilename(args_info.output_arg); + + // Go ! + filter->Update(); + + // this is the end my friend + return 0; +}// end main +//-------------------------------------------------------------------- + +#endif /* end #define CLITKVFRESAMPLE_CXX */ diff --git a/tools/clitkWarpImage.cxx b/tools/clitkWarpImage.cxx new file mode 100644 index 0000000..a42958e --- /dev/null +++ b/tools/clitkWarpImage.cxx @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + ------------------------------------------------------------------------*/ + +/* ================================================= + * @file clitkWarpImage.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk +#include "clitkWarpImage_ggo.h" +#include "clitkIO.h" +#include "clitkWarpImageGenericFilter.h" + + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkWarpImage, args_info); + CLITK_INIT; + + // Filter + clitk::WarpImageGenericFilter::Pointer genericFilter=clitk::WarpImageGenericFilter::New(); + + genericFilter->SetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +}// end main + +//-------------------------------------------------------------------- diff --git a/tools/clitkWarpImage.ggo b/tools/clitkWarpImage.ggo new file mode 100644 index 0000000..596c0aa --- /dev/null +++ b/tools/clitkWarpImage.ggo @@ -0,0 +1,30 @@ +#File clitkWarpImage.ggo +Package "clitkWarpImage" +version "1.0" +purpose "Warp an image. Output will have the extent (origin+ spacing*size) of the input." + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off + +section "I/O" + +option "input" i "Input image filename" string yes +option "output" o "Output image filename" string yes +option "vf" - "Vector field filename" string yes + + +section "Options" + +option "forward" f "Use forward warping (only linear interp)" flag off +option "spacing" s "The output spacing: 0=like the VF, 1= like the input image (interpolation of the VF prior to warp)" int no default="0" +option "pad" - "Edge padding value" float no default="0.0" + + +section "Interpolation: for image intensity and prior resampling of DVF" + +option "interp" - "Interpolation: 0=NN, 1=Linear, 2=BSpline, 3=BLUT" int no default="1" +option "interpOrder" - "Order if BLUT or BSpline (0-5)" int no default="3" +option "interpSF" - "Sampling factor if BLUT" int no default="20" +option "interpVF" - "Interpolation: 0=NN, 1=Linear, 2=BSpline, 3=BLUT" int no default="1" +option "interpVFOrder" - "Order if BLUT or BSpline (0-5)" int no default="3" +option "interpVFSF" - "Sampling factor if BLUT" int no default="20" diff --git a/tools/clitkWarpImageGenericFilter.cxx b/tools/clitkWarpImageGenericFilter.cxx new file mode 100644 index 0000000..01be19c --- /dev/null +++ b/tools/clitkWarpImageGenericFilter.cxx @@ -0,0 +1,55 @@ +#ifndef clitkWarpImageGenericFilter_cxx +#define clitkWarpImageGenericFilter_cxx + +/* ================================================= + * @file clitkWarpImageGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkWarpImageGenericFilter.h" + + +namespace clitk +{ + + + //----------------------------------------------------------- + // Constructor + //----------------------------------------------------------- + WarpImageGenericFilter::WarpImageGenericFilter() + { + m_Verbose=false; + m_InputFileName=""; + } + + + //----------------------------------------------------------- + // Update + //----------------------------------------------------------- + void WarpImageGenericFilter::Update() + { + // Read the Dimension and PixelType + int Dimension; + std::string PixelType; + ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType); + + + // Call UpdateWithDim + if(Dimension==2) UpdateWithDim<2>(PixelType); + else if(Dimension==3) UpdateWithDim<3>(PixelType); + // else if (Dimension==4)UpdateWithDim<4>(PixelType); + else + { + std::cout<<"Error, Only for 2 or 3 Dimensions!!!"< Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( WarpImageGenericFilter, LightObject ); + + + //---------------------------------------- + // Typedefs + //---------------------------------------- + + + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetArgsInfo(const gengetopt_args_info_clitkWarpImage & a) + { + m_ArgsInfo=a; + m_Verbose=m_ArgsInfo.verbose_flag; + m_InputFileName=m_ArgsInfo.input_arg; + } + + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(); + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + WarpImageGenericFilter(); + ~WarpImageGenericFilter() {}; + + + //---------------------------------------- + // Templated members + //---------------------------------------- + template void UpdateWithDim(std::string PixelType); + template void UpdateWithDimAndPixelType(); + + + //---------------------------------------- + // Data members + //---------------------------------------- + gengetopt_args_info_clitkWarpImage m_ArgsInfo; + bool m_Verbose; + std::string m_InputFileName; + + }; + + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkWarpImageGenericFilter.txx" +#endif + +#endif // #define clitkWarpImageGenericFilter_h diff --git a/tools/clitkWarpImageGenericFilter.txx b/tools/clitkWarpImageGenericFilter.txx new file mode 100644 index 0000000..6b33824 --- /dev/null +++ b/tools/clitkWarpImageGenericFilter.txx @@ -0,0 +1,223 @@ +#ifndef clitkWarpImageGenericFilter_txx +#define clitkWarpImageGenericFilter_txx + +/* ================================================= + * @file clitkWarpImageGenericFilter.txx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +namespace clitk +{ + + //------------------------------------------------------------------- + // Update with the number of dimensions + //------------------------------------------------------------------- + template + void + WarpImageGenericFilter::UpdateWithDim(std::string PixelType) + { + if (m_Verbose) std::cout << "Image was detected to be "<(); + } + // else if(PixelType == "unsigned_short"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_short..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + + else if (PixelType == "unsigned_char"){ + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_char..." << std::endl; + UpdateWithDimAndPixelType(); + } + + // else if (PixelType == "char"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed_char..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + else { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and float..." << std::endl; + UpdateWithDimAndPixelType(); + } + } + + + //------------------------------------------------------------------- + // Update with the number of dimensions and the pixeltype + //------------------------------------------------------------------- + template + void + WarpImageGenericFilter::UpdateWithDimAndPixelType() + { + + // ImageTypes + typedef itk::Image InputImageType; + typedef itk::Image OutputImageType; + typedef itk::Vector DisplacementType; + typedef itk::Image DeformationFieldType; + + + // Read the input + typedef itk::ImageFileReader InputReaderType; + typename InputReaderType::Pointer reader = InputReaderType::New(); + reader->SetFileName( m_InputFileName); + reader->Update(); + typename InputImageType::Pointer input= reader->GetOutput(); + + //Read the deformation field + typedef itk::ImageFileReader DeformationFieldReaderType; + typename DeformationFieldReaderType::Pointer deformationFieldReader= DeformationFieldReaderType::New(); + deformationFieldReader->SetFileName(m_ArgsInfo.vf_arg); + deformationFieldReader->Update(); + typename DeformationFieldType::Pointer deformationField =deformationFieldReader->GetOutput(); + + // Intensity interpolator + typedef clitk::GenericVectorInterpolator GenericInterpolatorType; + typename GenericInterpolatorType::Pointer genericInterpolator=GenericInterpolatorType::New(); + genericInterpolator->SetArgsInfo(m_ArgsInfo); + + + // ------------------------------------------- + // Spacing like DVF + // ------------------------------------------- + if (m_ArgsInfo.spacing_arg == 0) + { + // Calculate the region + typename DeformationFieldType::SizeType newSize; + for (unsigned int i=0 ; i GetLargestPossibleRegion().GetSize()[i]*input->GetSpacing()[i]/deformationField->GetSpacing()[i]); + + // Get the interpolator + typedef clitk::GenericVectorInterpolator GenericInterpolatorType; + typename GenericInterpolatorType::Pointer genericInterpolator=GenericInterpolatorType::New(); + genericInterpolator->SetArgsInfo(m_ArgsInfo); + + // Resample to match the extent of the input + typename itk::VectorResampleImageFilter::Pointer + resampler =itk::VectorResampleImageFilter::New(); + resampler->SetInput(deformationField); + resampler->SetOutputSpacing(deformationField->GetSpacing()); + resampler->SetSize(newSize); + resampler->SetOutputOrigin(input->GetOrigin()); + resampler->SetInterpolator(genericInterpolator->GetInterpolatorPointer()); + + // Update + if (m_Verbose) std::cout<< "Resampling the VF..." <Update(); + } + catch( itk::ExceptionObject & excp ) { + std::cerr << "Problem resampling the input vector field file" << std::endl; + std::cerr << excp << std::endl; + return; + } + deformationField= resampler->GetOutput(); + + } + + // ------------------------------------------- + // Spacing like input + // ------------------------------------------- + else + { + // Get size + typename DeformationFieldType::SizeType newSize; + for (unsigned int i=0 ; i GetLargestPossibleRegion().GetSize()[i]; + + // Resample to match the extent of the input + typename itk::VectorResampleImageFilter::Pointer + resampler =itk::VectorResampleImageFilter::New(); + resampler->SetInput(deformationField); + resampler->SetOutputSpacing(input->GetSpacing()); + resampler->SetSize(newSize); + resampler->SetOutputOrigin(input->GetOrigin()); + resampler->SetInterpolator(genericInterpolator->GetInterpolatorPointer()); + + // Update + if (m_Verbose) std::cout<< "Resampling the VF..." <Update(); + } + catch( itk::ExceptionObject & excp ) { + std::cerr << "Problem resampling the input vector field file" << std::endl; + std::cerr << excp << std::endl; + return; + } + deformationField= resampler->GetOutput(); + } + + + // ------------------------------------------- + // Forward Warp + // ------------------------------------------- + typename itk::ImageToImageFilter::Pointer warpFilter; + if (m_ArgsInfo.forward_flag) + { + //Forward warping: always linear + typedef clitk::ForwardWarpImageFilter ForwardWarpFilterType; + typename ForwardWarpFilterType::Pointer forwardWarpFilter= ForwardWarpFilterType::New(); + forwardWarpFilter->SetDeformationField( deformationField ); + forwardWarpFilter->SetEdgePaddingValue( static_cast(m_ArgsInfo.pad_arg) ); + warpFilter=forwardWarpFilter; + } + + // ------------------------------------------- + // Backward Warp + // ------------------------------------------- + else + { + // Get the interpolator + typedef clitk::GenericInterpolator GenericInterpolatorType; + typename GenericInterpolatorType::Pointer genericInterpolator=GenericInterpolatorType::New(); + genericInterpolator->SetArgsInfo(m_ArgsInfo); + + //Backward mapping + typedef itk::WarpImageFilter BackwardWarpFilterType; + typename BackwardWarpFilterType::Pointer backwardWarpFilter= BackwardWarpFilterType::New(); + backwardWarpFilter->SetDeformationField( deformationField ); + backwardWarpFilter->SetEdgePaddingValue( static_cast(m_ArgsInfo.pad_arg) ); + backwardWarpFilter->SetOutputSpacing( deformationField->GetSpacing() ); + backwardWarpFilter->SetOutputOrigin( input->GetOrigin() ); + backwardWarpFilter->SetOutputSize( deformationField->GetLargestPossibleRegion().GetSize() ); + typename itk::VectorResampleImageFilter::Pointer + resampler =itk::VectorResampleImageFilter::New(); + backwardWarpFilter->SetInterpolator(genericInterpolator->GetInterpolatorPointer()); + warpFilter=backwardWarpFilter; + } + + + // ------------------------------------------- + // Update + // ------------------------------------------- + warpFilter->SetInput(input); + if (m_Verbose) std::cout<< "Warping the input..." <Update(); + } + catch( itk::ExceptionObject & excp ) { + std::cerr << "Problem warping the input image" << std::endl; + std::cerr << excp << std::endl; + return; + } + + + // Output + typedef itk::ImageFileWriter WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(m_ArgsInfo.output_arg); + writer->SetInput(warpFilter->GetOutput()); + writer->Update(); + + } + + +}//end clitk + +#endif //#define clitkWarpImageGenericFilter_txx diff --git a/tools/clitkWriteDicomSeries.cxx b/tools/clitkWriteDicomSeries.cxx new file mode 100644 index 0000000..840c74e --- /dev/null +++ b/tools/clitkWriteDicomSeries.cxx @@ -0,0 +1,46 @@ +/*------------------------------------------------------------------------ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + ------------------------------------------------------------------------*/ + +/* ================================================= + * @file clitkWriteDicomSeries.cxx + * @author Jef Vandemeulebroucke + * @date 4th of August + * + * @brief Write a volume into a series with the header of another series + * + ===================================================*/ + + +// clitk +#include "clitkWriteDicomSeries_ggo.h" +#include "clitkIO.h" +#include "clitkWriteDicomSeriesGenericFilter.h" + + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkWriteDicomSeries, args_info); + CLITK_INIT; + + // Filter + typedef clitk::WriteDicomSeriesGenericFilter FilterType; + FilterType::Pointer genericFilter = FilterType::New(); + + genericFilter->SetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +}// end main + +//-------------------------------------------------------------------- diff --git a/tools/clitkWriteDicomSeries.ggo b/tools/clitkWriteDicomSeries.ggo new file mode 100644 index 0000000..7885274 --- /dev/null +++ b/tools/clitkWriteDicomSeries.ggo @@ -0,0 +1,14 @@ +#File clitkWriteDicomSeries.ggo +Package "clitkWriteDicomSeries" +version "1.0" +purpose "" + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off + +option "input" i "Input image filename" string yes +option "inputDir" d "Input dicom directory" string yes +option "outputDir" o "Output dicom directory" string yes +option "key" k "Keys of tags to modify" string no multiple default="0008|103e" +option "tag" t "Tags values" string no multiple default="MIDPOSITION" +option "midP" m "Modify tags using defaults, for MidPosition" flag off diff --git a/tools/clitkWriteDicomSeriesGenericFilter.cxx b/tools/clitkWriteDicomSeriesGenericFilter.cxx new file mode 100644 index 0000000..eb8fe92 --- /dev/null +++ b/tools/clitkWriteDicomSeriesGenericFilter.cxx @@ -0,0 +1,22 @@ +#ifndef clitkWriteDicomSeriesGenericFilter_cxx +#define clitkWriteDicomSeriesGenericFilter_cxx + +/* ================================================= + * @file clitkWriteDicomSeriesGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkWriteDicomSeriesGenericFilter.h" + + +namespace clitk +{ + + +} //end clitk + +#endif //#define clitkWriteDicomSeriesGenericFilter_cxx diff --git a/tools/clitkWriteDicomSeriesGenericFilter.h b/tools/clitkWriteDicomSeriesGenericFilter.h new file mode 100644 index 0000000..5a4172d --- /dev/null +++ b/tools/clitkWriteDicomSeriesGenericFilter.h @@ -0,0 +1,103 @@ +#ifndef clitkWriteDicomSeriesGenericFilter_h +#define clitkWriteDicomSeriesGenericFilter_h + +/* ================================================= + * @file clitkWriteDicomSeriesGenericFilter.h + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk include +#include "clitkIO.h" +#include "clitkCommon.h" +#include "clitkWriteDicomSeries_ggo.h" + +//itk include +#include "itkLightObject.h" +#include "itkGDCMImageIO.h" +#include "itkMetaDataDictionary.h" +#include "itkGDCMSeriesFileNames.h" +#include "itkImageSeriesReader.h" +#include "itkImageSeriesWriter.h" +#include +#include + +namespace clitk +{ + template + class ITK_EXPORT WriteDicomSeriesGenericFilter : public itk::LightObject + { + public: + //---------------------------------------- + // ITK + //---------------------------------------- + typedef WriteDicomSeriesGenericFilter Self; + typedef itk::LightObject Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( WriteDicomSeriesGenericFilter, LightObject ); + + + //---------------------------------------- + // Typedefs + //---------------------------------------- + + + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetArgsInfo(const args_info_type & a) + { + m_ArgsInfo=a; + m_Verbose=m_ArgsInfo.verbose_flag; + m_InputFileName=m_ArgsInfo.input_arg; + } + + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(); + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + WriteDicomSeriesGenericFilter(); + ~WriteDicomSeriesGenericFilter() {}; + + + //---------------------------------------- + // Templated members + //---------------------------------------- + template void UpdateWithDim(std::string PixelType); + template void UpdateWithDimAndPixelType(); + + + //---------------------------------------- + // Data members + //---------------------------------------- + args_info_type m_ArgsInfo; + bool m_Verbose; + std::string m_InputFileName; + + }; + + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkWriteDicomSeriesGenericFilter.txx" +#endif + +#endif // #define clitkWriteDicomSeriesGenericFilter_h diff --git a/tools/clitkWriteDicomSeriesGenericFilter.txx b/tools/clitkWriteDicomSeriesGenericFilter.txx new file mode 100644 index 0000000..2cabb04 --- /dev/null +++ b/tools/clitkWriteDicomSeriesGenericFilter.txx @@ -0,0 +1,193 @@ +#ifndef clitkWriteDicomSeriesGenericFilter_txx +#define clitkWriteDicomSeriesGenericFilter_txx + +/* ================================================= + * @file clitkWriteDicomSeriesGenericFilter.txx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +namespace clitk +{ + + + //----------------------------------------------------------- + // Constructor + //----------------------------------------------------------- + template + WriteDicomSeriesGenericFilter::WriteDicomSeriesGenericFilter() + { + m_Verbose=false; + m_InputFileName=""; + } + + + //----------------------------------------------------------- + // Update + //----------------------------------------------------------- + template + void WriteDicomSeriesGenericFilter::Update() + { + // Read the Dimension and PixelType + int Dimension; + std::string PixelType; + ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType); + + + // Call UpdateWithDim + if(Dimension==2) UpdateWithDim<2>(PixelType); + else if(Dimension==3) UpdateWithDim<3>(PixelType); + // else if (Dimension==4)UpdateWithDim<4>(PixelType); + else + { + std::cout<<"Error, Only for 2 or 3 Dimensions!!!"< + template + void + WriteDicomSeriesGenericFilter::UpdateWithDim(std::string PixelType) + { + if (m_Verbose) std::cout << "Image was detected to be "<(); + } + // else if(PixelType == "unsigned_short"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_short..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + + else if (PixelType == "unsigned_char"){ + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_char..." << std::endl; + UpdateWithDimAndPixelType(); + } + + // else if (PixelType == "char"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed_char..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + else { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and float..." << std::endl; + UpdateWithDimAndPixelType(); + } + } + + + //------------------------------------------------------------------- + // Update with the number of dimensions and the pixeltype + //------------------------------------------------------------------- + template + template + void + WriteDicomSeriesGenericFilter::UpdateWithDimAndPixelType() + { + + // ImageTypes + typedef itk::Image InputImageType; + typedef itk::Image OutputImageType; + + // Read the input (volumetric) + typedef itk::ImageFileReader InputReaderType; + typename InputReaderType::Pointer volumeReader = InputReaderType::New(); + volumeReader->SetFileName( m_InputFileName); + volumeReader->Update(); + typename InputImageType::Pointer input= volumeReader->GetOutput(); + + // Read the dicom directory + typedef itk::ImageSeriesReader< InputImageType > ReaderType; + typedef itk::GDCMImageIO ImageIOType; + typedef itk::GDCMSeriesFileNames NamesGeneratorType; + + ImageIOType::Pointer gdcmIO = ImageIOType::New(); + NamesGeneratorType::Pointer namesGenerator = NamesGeneratorType::New(); + namesGenerator->SetInputDirectory( m_ArgsInfo.inputDir_arg ); + typename ReaderType::FileNamesContainer filenames = namesGenerator->GetInputFileNames(); + + // Output the dicom files + unsigned int numberOfFilenames = filenames.size(); + if (m_Verbose) + { + std::cout << numberOfFilenames <<" were read in the directory "<* dictionary = reader->GetMetaDataDictionaryArray(); + + // Get keys + unsigned int numberOfKeysGiven=0; + if(m_ArgsInfo.midP_flag && m_ArgsInfo.key_given) + std::cerr<<"Error: both keys and midP option are given"<( *((*dictionary)[fni]), entryId, value ); + } + + // Output directory and filenames + itksys::SystemTools::MakeDirectory( m_ArgsInfo.outputDir_arg ); // create if it doesn't exist + typedef itk::ImageSeriesWriter SeriesWriterType; + typename SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New(); + + seriesWriter->SetInput( volumeReader->GetOutput() ); + seriesWriter->SetImageIO( gdcmIO ); + namesGenerator->SetOutputDirectory( m_ArgsInfo.outputDir_arg ); + seriesWriter->SetFileNames( namesGenerator->GetOutputFileNames() ); + //seriesWriter->SetMetaDataDictionaryArray( dictionary ); + seriesWriter->SetMetaDataDictionaryArray( dictionary ); + + // Write + try + { + seriesWriter->Update(); + } + catch( itk::ExceptionObject & excp ) + { + std::cerr << "Error: Exception thrown while writing the series!!" << std::endl; + std::cerr << excp << std::endl; + } + + } + + +}//end clitk + +#endif //#define clitkWriteDicomSeriesGenericFilter_txx diff --git a/tools/clitkZeroVF.cxx b/tools/clitkZeroVF.cxx new file mode 100644 index 0000000..ab1dc89 --- /dev/null +++ b/tools/clitkZeroVF.cxx @@ -0,0 +1,40 @@ +#ifndef clitkZeroVF_cxx +#define clitkZeroVF_cxx + + +/** + * @file clitkZeroVF.cxx + * @author Joel Schaerer + * @date July 20 10:14:53 2007 + * + * @brief Creates a VF filled with zeros the size of the input VF + * + */ + +// clitk include +#include "clitkZeroVF_ggo.h" +#include "clitkIO.h" +#include "clitkIOCommon.h" +#include "clitkZeroVFGenericFilter.h" + +int main( int argc, char *argv[] ) +{ + + // Init command line + GGO(clitkZeroVF, args_info); + CLITK_INIT; + + //Creation of the generic filter + clitk::ZeroVFGenericFilter::Pointer zeroVFGenericFilter= clitk::ZeroVFGenericFilter::New(); + + //Pass the parameters + zeroVFGenericFilter->SetInput(args_info.input_arg); + zeroVFGenericFilter->SetOutput(args_info.output_arg); + zeroVFGenericFilter->SetVerbose(args_info.verbose_flag); + + //update + zeroVFGenericFilter->Update(); + return EXIT_SUCCESS; +} +#endif + diff --git a/tools/clitkZeroVF.ggo b/tools/clitkZeroVF.ggo new file mode 100644 index 0000000..82c941f --- /dev/null +++ b/tools/clitkZeroVF.ggo @@ -0,0 +1,11 @@ +#File clitkZeroVF.ggo +#Author: Joel Schaerer +##Date : Tue 15 March 16.35 + +Package "clitk" +Version "Read a vector fields (.mhd, .vf, ..) and zero it" + +option "config" - "Config file" string no +option "input" i "Input VF filename" string yes +option "output" o "Output VF filename" string yes +option "verbose" v "Verbose" flag off diff --git a/tools/clitkZeroVFGenericFilter.cxx b/tools/clitkZeroVFGenericFilter.cxx new file mode 100644 index 0000000..1b7dc17 --- /dev/null +++ b/tools/clitkZeroVFGenericFilter.cxx @@ -0,0 +1,35 @@ +#ifndef CLITKINVERTVFGENERICFILTER_CXX +#define CLITKINVERTVFGENERICFILTER_CXX + +//clitk include +#include "clitkZeroVFGenericFilter.h" + + +namespace clitk { + + clitk::ZeroVFGenericFilter::ZeroVFGenericFilter() + { + m_Verbose=false; + } + + + void clitk::ZeroVFGenericFilter::Update() + { + //Get the image Dimension and PixelType + int Dimension; + std::string PixelType; + + clitk::ReadImageDimensionAndPixelType(m_InputName, Dimension, PixelType); + + if(Dimension==2) UpdateWithDim<2>(PixelType); + else if(Dimension==3) UpdateWithDim<3>(PixelType); + else + { + std::cout<<"Error, Only for 2 and 3 Dimensions!!!"< Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods) */ + itkTypeMacro( ZeroVFGenericFilter, ImageToImageFilter ); + + //Set Methods (inline) + void SetInput(const std::string m){m_InputName=m;} + void SetOutput(const std::string m){m_OutputName=m;} + void SetVerbose(const bool m){m_Verbose=m;} + + //Update + void Update( ); + + + protected: + + ZeroVFGenericFilter(); + ~ZeroVFGenericFilter() {}; + + //Templated members + template void UpdateWithDim(std::string PixelType); + template void UpdateWithDimAndPixelType(); + + std::string m_InputName; + std::string m_OutputName; + bool m_Verbose; + +}; + + +} // end namespace clitk +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkZeroVFGenericFilter.txx" +#endif + +#endif // #define __clitkZeroVFGenericFilter_h diff --git a/tools/clitkZeroVFGenericFilter.txx b/tools/clitkZeroVFGenericFilter.txx new file mode 100644 index 0000000..3a2f55f --- /dev/null +++ b/tools/clitkZeroVFGenericFilter.txx @@ -0,0 +1,52 @@ +#ifndef __clitkZeroVFGenericFilter_txx +#define __clitkZeroVFGenericFilter_txx + +#include "clitkZeroVFGenericFilter.h" + + +namespace clitk +{ + + template + void ZeroVFGenericFilter::UpdateWithDim(std::string PixelType) + { + if (PixelType=="double") + { + UpdateWithDimAndPixelType(); + } + else + { + UpdateWithDimAndPixelType(); + } + } + + + template + void ZeroVFGenericFilter::UpdateWithDimAndPixelType() + { + //Define the image type + typedef itk::Vector DisplacementType; + typedef itk::Image ImageType; + + //Read the image + typedef itk::ImageFileReader ImageReaderType; + typename ImageReaderType::Pointer reader= ImageReaderType::New(); + reader->SetFileName(m_InputName); + reader->Update(); // not very efficient :-p + typename ImageType::Pointer image =reader->GetOutput(); + DisplacementType zero; + zero.Fill(0); + image->FillBuffer(zero); + + //Write the output + typedef itk::ImageFileWriter WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(m_OutputName); + writer->SetInput(image); + writer->Update(); + } + + +} + +#endif diff --git a/tools/make_new_tool.sh b/tools/make_new_tool.sh new file mode 100755 index 0000000..6f73345 --- /dev/null +++ b/tools/make_new_tool.sh @@ -0,0 +1,8 @@ +#!/bin/bash +cp clitkSplitImage.ggo clitk$1.ggo +cp clitkSplitImage.cxx clitk$1.cxx +cp clitkSplitImageGenericFilter.h clitk$1GenericFilter.h +cp clitkSplitImageGenericFilter.txx clitk$1GenericFilter.txx +cp clitkSplitImageGenericFilter.cxx clitk$1GenericFilter.cxx + +sed -i "s/SplitImage/$1/g" clitk$1* diff --git a/vv/.gitignore b/vv/.gitignore new file mode 100644 index 0000000..e1993c8 --- /dev/null +++ b/vv/.gitignore @@ -0,0 +1,14 @@ +build/* +Louise +tests_jef +mctools +*.swp +Makefile +tags +doc +CVS +CMakeFiles +CMakeCache.txt +.vimrc +*_ggo.* +*.directory diff --git a/vv/CMakeLists.txt b/vv/CMakeLists.txt new file mode 100644 index 0000000..b68ceaa --- /dev/null +++ b/vv/CMakeLists.txt @@ -0,0 +1,294 @@ +cmake_minimum_required(VERSION 2.4) +#========================================================= +INCLUDE(${PROJECT_SOURCE_DIR}/cmake/common.cmake) +#========================================================= + +#Set a reasonable build mode default if the user hasn't set any +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE RelWithDebInfo) +endif (NOT CMAKE_BUILD_TYPE) + +#========================================================= +# Find ITK (required) +FIND_PACKAGE(ITK) +IF(ITK_FOUND) + INCLUDE(${ITK_USE_FILE}) +ELSE(ITK_FOUND) + MESSAGE(FATAL_ERROR + "Cannot build without ITK. Please set ITK_DIR.") +ENDIF(ITK_FOUND) +#========================================================= + +#========================================================= +# Find QT +FIND_PACKAGE(Qt4 REQUIRED) + +#========================================================= +INCLUDE_DIRECTORIES( + ${QT_INCLUDES} + ${VTK_INCLUDE_DIR} + ${QT_INCLUDE_DIR} + ${QT_QTGUI_INCLUDE_DIR} + ${QT_QTCORE_INCLUDE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ../common + ) + +#========================================================= + +#SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/bin) +#SET(LIBRARY_OUTPUT_PATH ${EXECUTABLE_OUTPUT_PATH}/../lib) + +#========================================================= +LINK_LIBRARIES ( + #ITKIO + clitkCommon + clitkFilters + ${QT_QTCORE_LIBRARY} + ${QT_QTGUI_LIBRARY} + vtkCommon + vtkRendering + vtkIO + vtkFiltering + vtkGraphics + vtkWidgets + vtkImaging + ) + +LINK_DIRECTORIES(${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR} ) + +#========================================================= + +OPTION(CLITK_VV_USE_BDCM "Build vv with Dicom selector bdcm" OFF) + +SET(vv_SRCS + vvInfoPanel.cxx + vvLinkPanel.cxx + vvOverlayPanel.cxx + vvLandmarksPanel.cxx + vvQProgressDialogITKCommand.cxx + vvQDicomSeriesSelector.cxx + QVTKWidget.cxx + QTreePushButton.cxx + vvResamplerDialog.cxx + vvSegmentationDialog.cxx + vvSurfaceViewerDialog.cxx + vvMainWindow.cxx + vvDeformationDialog.cxx + vvInit.cxx + vvImageWarp.cxx + nkitkXDRImageIOFactory.cxx + nkitkXDRImageIOReader.cxx + vvDeformableRegistration.cxx + vtkVOXImageWriter.cxx + vvInteractorStyleNavigator.cxx + vvSlicer.cxx + vvImageReader.cxx + vvImageReader.txx + vvImageWriter.cxx + vvImageWriter.txx + vvLandmarks.cxx + vvLandmarksGlyph.cxx + vvGlyphSource.cxx + vvGlyph2D.cxx + vvSlicerManager.cxx + vvSlicerManagerCommand.cxx + vvUtils.cxx + vvMaximumIntensityProjection.cxx + vvMesh.cxx + vvMeshActor.cxx + vvMeshReader.cxx + vvStructSelector.cxx + vvCropDialog.cxx + vvMidPosition.cxx + vvImageMapToWLColors.cxx + ) + +QT4_WRAP_CPP(vv_SRCS + vvMainWindow.h + QVTKWidget.h + QTreePushButton.h + vvInfoPanel.h + vvLinkPanel.h + vvOverlayPanel.h + vvLandmarksPanel.h + vvDocumentation.h + vvHelpDialog.h + vvProgressDialog.h + vvQDicomSeriesSelector.h + vvResamplerDialog.h + vvSegmentationDialog.h + vvSurfaceViewerDialog.h + vvDeformationDialog.h + vvSlicerManager.h + vvStructSelector.h + vvCropDialog.h + ) + +QT4_WRAP_UI(vv_UI_CXX + qt_ui/vvMainWindow.ui + qt_ui/vvInfoPanel.ui + qt_ui/vvLinkPanel.ui + qt_ui/vvOverlayPanel.ui + qt_ui/vvLandmarksPanel.ui + qt_ui/vvHelpDialog.ui + qt_ui/vvDocumentation.ui + qt_ui/vvProgressDialog.ui + qt_ui/vvDicomSeriesSelector.ui + qt_ui/vvSegmentationDialog.ui + qt_ui/vvSurfaceViewerDialog.ui + qt_ui/vvResamplerDialog.ui + qt_ui/vvDeformationDialog.ui + qt_ui/vvStructSelector.ui + qt_ui/vvCropDialog.ui + qt_ui/vvDummyWindow.ui #For testing + ) + +SET(vvUI_RCCS vvIcons.qrc) +QT4_ADD_RESOURCES(vv_SRCS ${vvUI_RCCS}) + +#========================================================= +#support for parallel deformable registration with OpenMP +IF(CMAKE_COMPILER_IS_GNUCC) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp -march=native") +ENDIF(CMAKE_COMPILER_IS_GNUCC) + +#========================================================= + +IF (CLITK_VV_USE_BDCM) + FIND_PACKAGE(bdcm) + IF(bdcm_FOUND) + INCLUDE(${bdcm_USE_FILE}) + ELSE(bdcm_FOUND) + MESSAGE(FATAL_ERROR + "Cannot build without BDCM. Please set BDCM_DIR.") + ENDIF(bdcm_FOUND) + #LINK_DIRECTORIES(/home/dsarrut/src/bdcm/build/) + #INCLUDE_DIRECTORIES(/home/dsarrut/src/bdcm/src2/) + + FIND_PACKAGE(GDCM) + IF(GDCM_FOUND) + INCLUDE(${GDCM_USE_FILE}) + ELSE(GDCM_FOUND) + MESSAGE(FATAL_ERROR + "Cannot build without GDCM. Please set GDCM_DIR.") + ENDIF(GDCM_FOUND) + +ENDIF (CLITK_VV_USE_BDCM) + +IF(WIN32) + SET(EXE_ICON vvIcon.rc) +ENDIF(WIN32) + +ADD_DEFINITIONS(-DQT_DLL) + +ADD_DEFINITIONS(-DQT_THREAD_SUPPORT) + +ADD_EXECUTABLE(vv ${vv_SRCS} vv.cxx ${vv_UI_CXX} ${EXE_ICON}) +TARGET_LINK_LIBRARIES(vv ${QT_LIBRARIES} ${ITK_LIBRARIES} ${VTK_LIBRARIES} ) + +#test executable +#QT4_WRAP_CPP(VVS_MOC_OUTFILE vvs.h) +#QT4_WRAP_UI(VVS_UI_OUTFILE qt_ui/vvDummyWindow.ui) +#ADD_EXECUTABLE(vvs ${vv_SRCS} vvs.cxx ${vv_UI_CXX} ${VVS_UI_OUTFILE} +#${VVS_MOC_OUTFILE} ${EXE_ICON}) +#TARGET_LINK_LIBRARIES(vvs ${QT_LIBRARIES} ${ITK_LIBRARIES} ${VTK_LIBRARIES} ) + +IF (CLITK_VV_USE_BDCM) + TARGET_LINK_LIBRARIES(vv ${QT_LIBRARIES} ${ITK_LIBRARIES} ${VTK_LIBRARIES} bdcm) +ELSE (CLITK_VV_USE_BDCM) + #TARGET_LINK_LIBRARIES(vv ${QT_LIBRARIES} ${ITK_LIBRARIES} ${VTK_LIBRARIES} ) +ENDIF (CLITK_VV_USE_BDCM) + +#IF( MINGW ) +# # resource compilation for MinGW +# ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/vvIcons.o +# COMMAND windres.exe -I${CMAKE_CURRENT_SOURCE_DIR} -i${CMAKE_CURRENT_SOURCE_DIR}/vvIcons.qrc -o ${CMAKE_CURRENT_BINARY_DIR}/vvIcons.o ) +# SET(vv_SRCS ${vv_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/vvIcons.o) +#ENDIF (MINGW) + +#IF( MINGW ) +# ADD_EXECUTABLE(vv WIN32 ${vv_SRCS} vv.cxx ${vv_UI_CXX} ${EXE_ICON}) +#ELSE (MINGW) +# ADD_EXECUTABLE(vv ${vv_SRCS} vv.cxx ${vv_UI_CXX} ${EXE_ICON}) +#ENDIF (MINGW) +#TARGET_LINK_LIBRARIES(vv ${QT_LIBRARIES} ${ITK_LIBRARIES} ${VTK_LIBRARIES} QVTKWidgetPlugin ) + +#========================================================= +# Installation file +INSTALL(TARGETS vv vv + RUNTIME DESTINATION bin CONFIGURATIONS relwithdebinfo + LIBRARY DESTINATION lib CONFIGURATIONS relwithdebinfo + ARCHIVE DESTINATION lib CONFIGURATIONS relwithdebinfo) +INSTALL(FILES ${vv_HDRS} DESTINATION include) + +IF(WIN32) + INSTALL (FILES ${CMAKE_CURRENT_SOURCE_DIR}/ducky.png DESTINATION bin) + INSTALL (FILES ${EXECUTABLE_OUTPUT_PATH}relwithdebinfo/vv.exe DESTINATION bin) + INSTALL (FILES ${QT_PLUGINS_DIR}/../bin/QtCore4.dll DESTINATION bin) + INSTALL (FILES ${QT_PLUGINS_DIR}/../bin/QtGui4.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkCommon.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtksys.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkRendering.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkGraphics.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkImaging.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkFiltering.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkGenericFiltering.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkIO.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/verdict.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/QVTK.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/QVTKWidgetPlugin.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkDICOMParser.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkexoIIc.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkexpat.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkmetaio.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkftgl.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkfreetype.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkGenericFiltering.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkHybrid.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkInfovis.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkjpeg.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtklibxml2.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkNetCDF.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkpng.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtktiff.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkViews.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkVolumeRendering.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkWidgets.dll DESTINATION bin) + INSTALL (FILES ${VTK_DIR}/bin/relwithdebinfo/vtkzlib.dll DESTINATION bin) +ENDIF(WIN32) + +IF(UNIX) + INSTALL (FILES ${EXECUTABLE_OUTPUT_PATH}/vv DESTINATION bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE) + INSTALL (FILES ${CMAKE_CURRENT_SOURCE_DIR}/icons/ducky.png DESTINATION bin) + INSTALL (FILES ${EXECUTABLE_OUTPUT_PATH}vv DESTINATION bin) +ENDIF(UNIX) + +#========================================================= +# CPack options +INCLUDE(InstallRequiredSystemLibraries) + +SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "vv, the 4D slicer : let's jump into a new dimension !") +SET(CPACK_PACKAGE_VENDOR "Creatis, CLB/RIO Team") +SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/ReadMe.txt") +SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt") +SET(CPACK_PACKAGE_VERSION_MAJOR "1") +SET(CPACK_PACKAGE_VERSION_MINOR "0") +SET(CPACK_PACKAGE_VERSION_PATCH "0") +SET(CPACK_PACKAGE_INSTALL_DIRECTORY "vv ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}") +IF(WIN32 AND NOT UNIX) + # There is a bug in NSI that does not handle full unix paths properly. Make + # sure there is at least one set of four (4) backlasshes. + SET(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}\\\\ducky.png") + SET(CPACK_NSIS_INSTALLED_ICON_NAME "bin/relwithdebinfo\\\\vv.exe") + SET(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} The 4D slicer") + SET(CPACK_NSIS_HELP_LINK "http://www.creatis.insa-lyon.fr/rio") + SET(CPACK_NSIS_URL_INFO_ABOUT "http://www.creatis.insa-lyon.fr/rio") + SET(CPACK_NSIS_MODIFY_PATH ON) +ELSE(WIN32 AND NOT UNIX) + SET(CPACK_STRIP_FILES "bin/vv") + SET(CPACK_SOURCE_STRIP_FILES "") +ENDIF(WIN32 AND NOT UNIX) +SET(CPACK_PACKAGE_EXECUTABLES "vv" "vv") +INCLUDE(CPack) diff --git a/vv/License.txt b/vv/License.txt new file mode 100644 index 0000000..cee7f6a --- /dev/null +++ b/vv/License.txt @@ -0,0 +1,44 @@ +VV License + +VV is copyrighted as an open-source, Berkeley-style license. It allows +unrestricted use, including use in commercial products. The complete +copyright is shown below. + +/*========================================================================= + +Copyright (c) 2008 CLB / CREATIS-LRMN + +CLB = Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LMRN = Centre de Recherche et d'Applications en Traitement de l'Image http://www.creatis.insa-lyon.fr + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of CLB, CREATIS-LRMN, nor the names of any contributor (CNRS, INSERM, + INSA, Universite Claude-Bernard Lyon I), may be used to endorse or promote + products derived from this software without specific prior written permission. + + * Modified source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================*/ \ No newline at end of file diff --git a/vv/QTreePushButton.cxx b/vv/QTreePushButton.cxx new file mode 100644 index 0000000..a8d24db --- /dev/null +++ b/vv/QTreePushButton.cxx @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: QTreePushButton.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:58 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#include "QTreePushButton.h" + +QTreePushButton::QTreePushButton():QPushButton() +{ + m_item = NULL; + m_index = 0; + m_column = 0; + connect(this,SIGNAL(clicked()),this, SLOT(clickedIntoATree())); +} + +void QTreePushButton::clickedIntoATree() +{ + emit clickedInto(m_item,m_column); + emit clickedInto(m_index,m_column); +} diff --git a/vv/QTreePushButton.h b/vv/QTreePushButton.h new file mode 100644 index 0000000..80c98be --- /dev/null +++ b/vv/QTreePushButton.h @@ -0,0 +1,63 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: QTreePushButton.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:58 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef QTreePushButton_h +#define QTreePushButton_h + +#include +#include +#include + +class QTreePushButton : public QPushButton +{ + Q_OBJECT + +public: + QTreePushButton(); + + void setIndex(int index) { + m_index = index; + } + void setItem(QTreeWidgetItem* item) { + m_item = item; + } + void setColumn(int column) { + m_column = column; + } + +public slots: + void clickedIntoATree(); + +signals: + void clickedInto(QTreeWidgetItem* item,int column); + void clickedInto(int index,int column); + +private: + QTreeWidgetItem* m_item; + int m_index; + int m_column; +}; +#endif diff --git a/vv/QVTKWidget.cxx b/vv/QVTKWidget.cxx new file mode 100644 index 0000000..475e99a --- /dev/null +++ b/vv/QVTKWidget.cxx @@ -0,0 +1,3029 @@ +/* + + * Copyright 2004 Sandia Corporation. + + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + + * license for use of this work by or on behalf of the + + * U.S. Government. Redistribution and use in source and binary forms, with + + * or without modification, are permitted provided that this Notice and any + + * statement of authorship are reproduced on all copies. + + */ + + + +/*======================================================================== + + For general information about using VTK and Qt, see: + + http://www.trolltech.com/products/3rdparty/vtksupport.html + +=========================================================================*/ + + + +/*======================================================================== + + !!! WARNING for those who want to contribute code to this file. + + !!! If you use a commercial edition of Qt, you can modify this code. + + !!! If you use an open source version of Qt, you are free to modify + + !!! and use this code within the guidelines of the GPL license. + + !!! Unfortunately, you cannot contribute the changes back into this + + !!! file. Doing so creates a conflict between the GPL and BSD-like VTK + + !!! license. + +=========================================================================*/ + + + +#ifdef _MSC_VER + +// Disable warnings that Qt headers give. + +#pragma warning(disable:4127) + +#pragma warning(disable:4512) + +#endif + + + +#include "QVTKWidget.h" + + + +#include "qevent.h" + +#include "qapplication.h" + +#include "qpainter.h" + +#include "qsignalmapper.h" + +#include "qtimer.h" + +#if QT_VERSION >= 0x040000 && defined(Q_WS_X11) + +#include "qx11info_x11.h" + +#endif + + + +#include "vtkstd/map" + +#include "vtkInteractorStyleTrackballCamera.h" + +#include "vtkRenderWindow.h" + +#if defined(Q_WS_MAC) + +# include "vtkCarbonRenderWindow.h" + +#endif + +#include "vtkCommand.h" + +#include "vtkOStrStreamWrapper.h" + +#include "vtkObjectFactory.h" + +#include "vtkCallbackCommand.h" + +#include "vtkConfigure.h" + +#include "vtkToolkits.h" + +#include "vtkUnsignedCharArray.h" + + + + + +// function to get VTK keysyms from ascii characters + +static const char* ascii_to_key_sym(int); + +// function to get VTK keysyms from Qt keys + +static const char* qt_key_to_key_sym(Qt::Key); + + + +// function to dirty cache when a render occurs. + +static void dirty_cache(vtkObject *, unsigned long, void *, void *); + + + + + + + +#if QT_VERSION < 0x040000 + +/*! constructor */ + +QVTKWidget::QVTKWidget(QWidget* parent, const char* name, Qt::WFlags f) + +#if QT_VERSION < 0x030000 + + : + QWidget(parent, name, f | 0x10000000) // WWinOwnDC + +#else + + : QWidget(parent, name, f | Qt::WWinOwnDC ) + +#endif + + , mRenWin(NULL), + + cachedImageCleanFlag(false), + + automaticImageCache(false), maxImageCacheRenderRate(1.0) + +{ + + // no background + + this->setBackgroundMode( Qt::NoBackground ); + + + + // default to strong focus + + this->setFocusPolicy(QWidget::StrongFocus); + + + + // default to enable mouse events when a mouse button isn't down + + // so we can send enter/leave events to VTK + + this->setMouseTracking(true); + + + + // set expanding to take up space for better default layouts + + this->setSizePolicy( + + QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) + + ); + + + + this->mCachedImage = vtkUnsignedCharArray::New(); + +} + +#endif + + + + + +#if QT_VERSION >= 0x040000 + +/*! constructor */ + +QVTKWidget::QVTKWidget(QWidget* p, Qt::WFlags f) + + : QWidget(p, f | Qt::MSWindowsOwnDC), mRenWin(NULL), + + cachedImageCleanFlag(false), + + automaticImageCache(false), maxImageCacheRenderRate(1.0) + + + +{ + + // no background + + this->setAttribute(Qt::WA_NoBackground); + + // no double buffering + + this->setAttribute(Qt::WA_PaintOnScreen); + + + + // default to strong focus + + this->setFocusPolicy(Qt::StrongFocus); + + + + // default to enable mouse events when a mouse button isn't down + + // so we can send enter/leave events to VTK + + this->setMouseTracking(true); + + + + // set expanding to take up space for better default layouts + + this->setSizePolicy( + + QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) + + ); + + + + this->mCachedImage = vtkUnsignedCharArray::New(); + + + +#if defined(Q_WS_MAC) + + this->DirtyRegionHandler = 0; + + this->DirtyRegionHandlerUPP = 0; + +#endif + + + +} + +#endif + + + + + +/*! destructor */ + + + +QVTKWidget::~QVTKWidget() + +{ + + // get rid of the VTK window + + this->SetRenderWindow(NULL); + + + + this->mCachedImage->Delete(); + +} + + + +/*! get the render window + + */ + +vtkRenderWindow* QVTKWidget::GetRenderWindow() + +{ + + if (!this->mRenWin) + + { + + // create a default vtk window + + vtkRenderWindow* win = vtkRenderWindow::New(); + + this->SetRenderWindow(win); + + win->Delete(); + + } + + + + return this->mRenWin; + +} + + + + + + + +/*! set the render window + + this will bind a VTK window with the Qt window + + it'll also replace an existing VTK window + +*/ + +void QVTKWidget::SetRenderWindow(vtkRenderWindow* w) + +{ + + // do nothing if we don't have to + + if (w == this->mRenWin) + + { + + return; + + } + + + + // unregister previous window + + if (this->mRenWin) + + { + + //clean up window as one could remap it + + if (this->mRenWin->GetMapped()) + + { + + this->mRenWin->Finalize(); + + } + + this->mRenWin->SetDisplayId(NULL); + + this->mRenWin->SetParentId(NULL); + + this->mRenWin->SetWindowId(NULL); + + this->mRenWin->UnRegister(NULL); + + } + + + + // now set the window + + this->mRenWin = w; + + + + if (this->mRenWin) + + { + + // register new window + + this->mRenWin->Register(NULL); + + + + // if it is mapped somewhere else, unmap it + + if (this->mRenWin->GetMapped()) + + { + + this->mRenWin->Finalize(); + + } + + + +#ifdef Q_WS_X11 + + // give the qt display id to the vtk window + +#if QT_VERSION < 0x040000 + + this->mRenWin->SetDisplayId( this->x11Display() ); + +#else + + this->mRenWin->SetDisplayId(QX11Info::display()); + +#endif + +#endif + + + + // special x11 setup + + x11_setup_window(); + + + + // give the qt window id to the vtk window + + this->mRenWin->SetWindowId( reinterpret_cast(this->winId())); + + + + // mac compatibility issues + +#if defined(Q_WS_MAC) && (QT_VERSION < 0x040000) + + this->mRenWin->SetWindowId( NULL ); + + static_cast(this->mRenWin)->SetRootWindow( + + reinterpret_cast(this->handle())); + +#endif + + + + + + // tell the vtk window what the size of this window is + + this->mRenWin->vtkRenderWindow::SetSize(this->width(), this->height()); + + this->mRenWin->vtkRenderWindow::SetPosition(this->x(), this->y()); + + + + // have VTK start this window and create the necessary graphics resources + + if (isVisible()) + + { + + this->mRenWin->Start(); + +#if defined (Q_WS_MAC) && (QT_VERSION < 0x040000) + + macFixRect(); + +#endif + + } + + + + // if an interactor wasn't provided, we'll make one by default + + if (!this->mRenWin->GetInteractor()) + + { + + // create a default interactor + + QVTKInteractor* iren = QVTKInteractor::New(); + + this->mRenWin->SetInteractor(iren); + + iren->Initialize(); + + + + // now set the default style + + vtkInteractorStyle* s = vtkInteractorStyleTrackballCamera::New(); + + iren->SetInteractorStyle(s); + + + + iren->Delete(); + + s->Delete(); + + } + + + + // tell the interactor the size of this window + + this->mRenWin->GetInteractor()->SetSize(this->width(), this->height()); + + + + // Add an observer to monitor when the image changes. Should work most + + // of the time. The application will have to call + + // markCachedImageAsDirty for any other case. + + vtkCallbackCommand *cbc = vtkCallbackCommand::New(); + + cbc->SetClientData(this); + + cbc->SetCallback(dirty_cache); + + this->mRenWin->AddObserver(vtkCommand::EndEvent, cbc); + + cbc->Delete(); + + } + + + +#if defined(Q_WS_MAC) && QT_VERSION >= 0x040000 + + if (mRenWin && !this->DirtyRegionHandlerUPP) + + { + + this->DirtyRegionHandlerUPP = NewEventHandlerUPP(QVTKWidget::DirtyRegionProcessor); + + static EventTypeSpec events[] = { {'cute', 20} }; + + // kEventClassQt, kEventQtRequestWindowChange from qt_mac_p.h + + // Suggested by Sam Magnuson at Trolltech as best portabile hack + + // around Apple's missing functionality in HI Toolbox. + + InstallEventHandler(GetApplicationEventTarget(), this->DirtyRegionHandlerUPP, + + GetEventTypeCount(events), events, + + reinterpret_cast(this), &this->DirtyRegionHandler); + + } + + else if (!mRenWin && this->DirtyRegionHandlerUPP) + + { + + RemoveEventHandler(this->DirtyRegionHandler); + + DisposeEventHandlerUPP(this->DirtyRegionHandlerUPP); + + this->DirtyRegionHandler = 0; + + this->DirtyRegionHandlerUPP = 0; + + } + +#endif + +} + + + + + + + +/*! get the Qt/VTK interactor + + */ + +QVTKInteractor* QVTKWidget::GetInteractor() + +{ + + return QVTKInteractor + + ::SafeDownCast(this->GetRenderWindow()->GetInteractor()); + +} + + + +void QVTKWidget::markCachedImageAsDirty() + +{ + + if (this->cachedImageCleanFlag) + + { + + this->cachedImageCleanFlag = false; + + emit cachedImageDirty(); + + } + +} + + + +void QVTKWidget::saveImageToCache() + +{ + + if (this->cachedImageCleanFlag) + + { + + return; + + } + + + + this->mRenWin->GetPixelData(0, 0, this->width()-1, this->height()-1, 1, + + this->mCachedImage); + + this->cachedImageCleanFlag = true; + + emit cachedImageClean(); + +} + + + +void QVTKWidget::setAutomaticImageCacheEnabled(bool flag) + +{ + + this->automaticImageCache = flag; + + if (!flag) + + { + + this->mCachedImage->Initialize(); + + } + +} + +bool QVTKWidget::isAutomaticImageCacheEnabled() const + +{ + + return this->automaticImageCache; + +} + + + +void QVTKWidget::setMaxRenderRateForImageCache(double rate) + +{ + + this->maxImageCacheRenderRate = rate; + +} + +double QVTKWidget::maxRenderRateForImageCache() const + +{ + + return this->maxImageCacheRenderRate; + +} + + + +vtkUnsignedCharArray* QVTKWidget::cachedImage() + +{ + + // Make sure image is up to date. + + this->paintEvent(NULL); + + this->saveImageToCache(); + + + + return this->mCachedImage; + +} + + + +/*! overloaded Qt's event handler to capture additional keys that Qt has + + default behavior for (for example the Tab and Shift-Tab key) + +*/ + +bool QVTKWidget::event(QEvent* e) + +{ + +#if QT_VERSION >= 0x040000 + + if (e->type() == QEvent::ParentAboutToChange) + + { + + this->markCachedImageAsDirty(); + + if (this->mRenWin) + + { + + // Finalize the window to remove graphics resources associated with + + // this window + + if (this->mRenWin->GetMapped()) + + { + + this->mRenWin->Finalize(); + + } + + } + + } + + else if (e->type() == QEvent::ParentChange) + + { + + if (this->mRenWin) + + { + + x11_setup_window(); + + // connect to new window + + this->mRenWin->SetWindowId( reinterpret_cast(this->winId())); + + + + // start up the window to create graphics resources for this window + + if (isVisible()) + + { + + this->mRenWin->Start(); + + } + + } + + } + +#endif + + + + if (QObject::event(e)) + + { + + return TRUE; + + } + + + + if (e->type() == QEvent::KeyPress) + + { + + QKeyEvent* ke = static_cast(e); + + this->keyPressEvent(ke); + + return ke->isAccepted(); + + } + + + + return QWidget::event(e); + +} + + + + + +/*! handle resize event + + */ + +void QVTKWidget::resizeEvent(QResizeEvent* e) + +{ + + QWidget::resizeEvent(e); + + + + if (!this->mRenWin) + + { + + return; + + } + + + + // give the size to the interactor and vtk window + + this->mRenWin->vtkRenderWindow::SetSize(this->width(), this->height()); + + if (this->mRenWin->GetInteractor()) + + { + + this->mRenWin->GetInteractor()->SetSize(this->width(), this->height()); + + } + + this->markCachedImageAsDirty(); + + + +#if defined (Q_WS_MAC) && (QT_VERSION < 0x040000) + + macFixRect(); + +#endif + +} + + + +void QVTKWidget::moveEvent(QMoveEvent* e) + +{ + + QWidget::moveEvent(e); + + + + if (!this->mRenWin) + + { + + return; + + } + + + + // give the size to the interactor and vtk window + + this->mRenWin->vtkRenderWindow::SetPosition(this->x(), this->y()); + + + +#if defined (Q_WS_MAC) && (QT_VERSION < 0x040000) + + macFixRect(); + +#endif + +} + + + +/*! handle paint event + + */ + +void QVTKWidget::paintEvent(QPaintEvent* ) + +{ + + vtkRenderWindowInteractor* iren = NULL; + + if (this->mRenWin) + + { + + iren = this->mRenWin->GetInteractor(); + + } + + + + if (!iren || !iren->GetEnabled()) + + { + + return; + + } + + + + + + // if we have a saved image, use it + + if (this->cachedImageCleanFlag) + + { + + // put cached image into back buffer if we can + + this->mRenWin->SetPixelData(0, 0, this->width()-1, this->height()-1, + + this->mCachedImage, + + !this->mRenWin->GetDoubleBuffer()); + + // swap buffers, if double buffering + + this->mRenWin->Frame(); + + // or should we just put it on the front buffer? + + return; + + } + + + + iren->Render(); + + + + // In Qt 4.1+ let's support redirected painting + +#if QT_VERSION >= 0x040100 + + // if redirected, let's grab the image from VTK, and paint it to the device + + QPaintDevice* device = QPainter::redirected(this); + + if (device != NULL && device != this) + + { + + int w = this->width(); + + int h = this->height(); + + QImage img(w, h, QImage::Format_RGB32); + + vtkUnsignedCharArray* pixels = vtkUnsignedCharArray::New(); + + pixels->SetArray(img.bits(), w*h*4, 1); + + this->mRenWin->GetRGBACharPixelData(0, 0, w-1, h-1, 1, pixels); + + pixels->Delete(); + + img = img.rgbSwapped(); + + img = img.mirrored(); + + + + QPainter painter(this); + + painter.drawImage(QPointF(0.0,0.0), img); + + return; + + } + +#endif + +} + + + +/*! handle mouse press event + + */ + +void QVTKWidget::mousePressEvent(QMouseEvent* e) + +{ + + + + // Emit a mouse press event for anyone who might be interested + + emit mouseEvent(e); + + + + vtkRenderWindowInteractor* iren = NULL; + + if (this->mRenWin) + + { + + iren = this->mRenWin->GetInteractor(); + + } + + + + if (!iren || !iren->GetEnabled()) + + { + + return; + + } + + + + // give interactor the event information + +#if QT_VERSION < 0x040000 + + iren->SetEventInformationFlipY(e->x(), e->y(), + + (e->state() & Qt::ControlButton) > 0 ? 1 : 0, + + (e->state() & Qt::ShiftButton ) > 0 ? 1 : 0, 0, + + e->type() == QEvent::MouseButtonDblClick ? 1 : 0); + +#else + + iren->SetEventInformationFlipY(e->x(), e->y(), + + (e->modifiers() & Qt::ControlModifier) > 0 ? 1 : 0, + + (e->modifiers() & Qt::ShiftModifier ) > 0 ? 1 : 0, + + 0, + + e->type() == QEvent::MouseButtonDblClick ? 1 : 0); + +#endif + + + + // invoke appropriate vtk event + + switch (e->button()) + + { + + case Qt::LeftButton: + + iren->InvokeEvent(vtkCommand::LeftButtonPressEvent, e); + + break; + + + + case Qt::MidButton: + + iren->InvokeEvent(vtkCommand::MiddleButtonPressEvent, e); + + break; + + + + case Qt::RightButton: + + iren->InvokeEvent(vtkCommand::RightButtonPressEvent, e); + + break; + + + + default: + + break; + + } + +} + + + +/*! handle mouse move event + + */ + +void QVTKWidget::mouseMoveEvent(QMouseEvent* e) + +{ + + vtkRenderWindowInteractor* iren = NULL; + + if (this->mRenWin) + + { + + iren = this->mRenWin->GetInteractor(); + + } + + + + if (!iren || !iren->GetEnabled()) + + { + + return; + + } + + + + // give interactor the event information + +#if QT_VERSION < 0x040000 + + iren->SetEventInformationFlipY(e->x(), e->y(), + + (e->state() & Qt::ControlButton) > 0 ? 1 : 0, + + (e->state() & Qt::ShiftButton ) > 0 ? 1 : 0); + +#else + + iren->SetEventInformationFlipY(e->x(), e->y(), + + (e->modifiers() & Qt::ControlModifier) > 0 ? 1 : 0, + + (e->modifiers() & Qt::ShiftModifier ) > 0 ? 1 : 0); + +#endif + + + + // invoke vtk event + + iren->InvokeEvent(vtkCommand::MouseMoveEvent, e); + +} + + + + + +/*! handle enter event + + */ + +void QVTKWidget::enterEvent(QEvent* e) + +{ + + vtkRenderWindowInteractor* iren = NULL; + + if (this->mRenWin) + + { + + iren = this->mRenWin->GetInteractor(); + + } + + + + if (!iren || !iren->GetEnabled()) + + { + + return; + + } + + this->setFocus(); + + iren->InvokeEvent(vtkCommand::EnterEvent, e); + +} + + + +/*! handle leave event + + */ + +void QVTKWidget::leaveEvent(QEvent* e) + +{ + + vtkRenderWindowInteractor* iren = NULL; + + if (this->mRenWin) + + { + + iren = this->mRenWin->GetInteractor(); + + } + + + + if (!iren || !iren->GetEnabled()) + + { + + return; + + } + + + + iren->InvokeEvent(vtkCommand::LeaveEvent, e); + +} + + + +/*! handle mouse release event + + */ + +void QVTKWidget::mouseReleaseEvent(QMouseEvent* e) + +{ + + vtkRenderWindowInteractor* iren = NULL; + + if (this->mRenWin) + + { + + iren = this->mRenWin->GetInteractor(); + + } + + + + if (!iren || !iren->GetEnabled()) + + { + + return; + + } + + + + // give vtk event information + +#if QT_VERSION < 0x040000 + + iren->SetEventInformationFlipY(e->x(), e->y(), + + (e->state() & Qt::ControlButton) > 0 ? 1 : 0, + + (e->state() & Qt::ShiftButton ) > 0 ? 1 : 0); + +#else + + iren->SetEventInformationFlipY(e->x(), e->y(), + + (e->modifiers() & Qt::ControlModifier) > 0 ? 1 : 0, + + (e->modifiers() & Qt::ShiftModifier ) > 0 ? 1 : 0); + +#endif + + + + // invoke appropriate vtk event + + switch (e->button()) + + { + + case Qt::LeftButton: + + iren->InvokeEvent(vtkCommand::LeftButtonReleaseEvent, e); + + break; + + + + case Qt::MidButton: + + iren->InvokeEvent(vtkCommand::MiddleButtonReleaseEvent, e); + + break; + + + + case Qt::RightButton: + + iren->InvokeEvent(vtkCommand::RightButtonReleaseEvent, e); + + break; + + + + default: + + break; + + } + +} + + + +/*! handle key press event + + */ + +void QVTKWidget::keyPressEvent(QKeyEvent* e) + +{ + + vtkRenderWindowInteractor* iren = NULL; + + if (this->mRenWin) + + { + + iren = this->mRenWin->GetInteractor(); + + } + + + + if (!iren || !iren->GetEnabled()) + + { + + return; + + } + + + + // get key and keysym information + +#if QT_VERSION < 0x040000 + + int ascii_key = e->text().length() ? e->text().unicode()->latin1() : 0; + +#else + + int ascii_key = e->text().length() ? e->text().unicode()->toLatin1() : 0; + +#endif + + const char* keysym = ascii_to_key_sym(ascii_key); + + if (!keysym) + + { + + // get virtual keys + + keysym = qt_key_to_key_sym(static_cast(e->key())); + + } + + + + if (!keysym) + + { + + keysym = "None"; + + } + + + + // give interactor event information + +#if QT_VERSION < 0x040000 + + iren->SetKeyEventInformation( + + (e->state() & Qt::ControlButton), + + (e->state() & Qt::ShiftButton), + + ascii_key, e->count(), keysym); + +#else + + iren->SetKeyEventInformation( + + (e->modifiers() & Qt::ControlModifier), + + (e->modifiers() & Qt::ShiftModifier), + + ascii_key, e->count(), keysym); + +#endif + + + + // invoke vtk event + + iren->InvokeEvent(vtkCommand::KeyPressEvent, e); + + + + // invoke char event only for ascii characters + + if (ascii_key) + + { + + iren->InvokeEvent(vtkCommand::CharEvent, e); + + } + +} + + + +/*! handle key release event + + */ + +void QVTKWidget::keyReleaseEvent(QKeyEvent* e) + +{ + + + + vtkRenderWindowInteractor* iren = NULL; + + if (this->mRenWin) + + { + + iren = this->mRenWin->GetInteractor(); + + } + + + + if (!iren || !iren->GetEnabled()) + + { + + return; + + } + + + + // get key and keysym info + +#if QT_VERSION < 0x040000 + + int ascii_key = e->text().length() ? e->text().unicode()->latin1() : 0; + +#else + + int ascii_key = e->text().length() ? e->text().unicode()->toLatin1() : 0; + +#endif + + const char* keysym = ascii_to_key_sym(ascii_key); + + if (!keysym) + + { + + // get virtual keys + + keysym = qt_key_to_key_sym((Qt::Key)e->key()); + + } + + + + if (!keysym) + + { + + keysym = "None"; + + } + + + + // give event information to interactor + +#if QT_VERSION < 0x040000 + + iren->SetKeyEventInformation( + + (e->state() & Qt::ControlButton), + + (e->state() & Qt::ShiftButton), + + ascii_key, e->count(), keysym); + +#else + + iren->SetKeyEventInformation( + + (e->modifiers() & Qt::ControlModifier), + + (e->modifiers() & Qt::ShiftModifier), + + ascii_key, e->count(), keysym); + +#endif + + + + // invoke vtk event + + iren->InvokeEvent(vtkCommand::KeyReleaseEvent, e); + +} + + + +#ifndef QT_NO_WHEELEVENT + +void QVTKWidget::wheelEvent(QWheelEvent* e) + +{ + + vtkRenderWindowInteractor* iren = NULL; + + if (this->mRenWin) + + { + + iren = this->mRenWin->GetInteractor(); + + } + + + + if (!iren || !iren->GetEnabled()) + + { + + return; + + } + + + +// VTK supports wheel mouse events only in version 4.5 or greater + + // give event information to interactor + +#if QT_VERSION < 0x040000 + + iren->SetEventInformationFlipY(e->x(), e->y(), + + (e->state() & Qt::ControlButton) > 0 ? 1 : 0, + + (e->state() & Qt::ShiftButton ) > 0 ? 1 : 0); + +#else + + iren->SetEventInformationFlipY(e->x(), e->y(), + + (e->modifiers() & Qt::ControlModifier) > 0 ? 1 : 0, + + (e->modifiers() & Qt::ShiftModifier ) > 0 ? 1 : 0); + +#endif + + + + // invoke vtk event + + // if delta is positive, it is a forward wheel event + + if (e->delta() > 0) + + { + + iren->InvokeEvent(vtkCommand::MouseWheelForwardEvent, e); + + } + + else + + { + + iren->InvokeEvent(vtkCommand::MouseWheelBackwardEvent, e); + + } + +} + +#endif + + + +void QVTKWidget::focusInEvent(QFocusEvent*) + +{ + + // These prevent updates when the window + + // gains or loses focus. By default, Qt + + // does an update because the color group's + + // active status changes. We don't even use + + // color groups so we do nothing here. + +} + + + +void QVTKWidget::focusOutEvent(QFocusEvent*) + +{ + + // These prevent updates when the window + + // gains or loses focus. By default, Qt + + // does an update because the color group's + + // active status changes. We don't even use + + // color groups so we do nothing here. + +} + + + + + +void QVTKWidget::contextMenuEvent(QContextMenuEvent* e) + +{ + + vtkRenderWindowInteractor* iren = NULL; + + if (this->mRenWin) + + { + + iren = this->mRenWin->GetInteractor(); + + } + + + + if (!iren || !iren->GetEnabled()) + + { + + return; + + } + + + + // give interactor the event information + +#if QT_VERSION < 0x040000 + + iren->SetEventInformationFlipY(e->x(), e->y(), + + (e->state() & Qt::ControlButton) > 0 ? 1 : 0, + + (e->state() & Qt::ShiftButton ) > 0 ? 1 : 0); + +#else + + iren->SetEventInformationFlipY(e->x(), e->y(), + + (e->modifiers() & Qt::ControlModifier) > 0 ? 1 : 0, + + (e->modifiers() & Qt::ShiftModifier ) > 0 ? 1 : 0); + +#endif + + + + // invoke event and pass qt event for additional data as well + + iren->InvokeEvent(QVTKWidget::ContextMenuEvent, e); + + + +} + + + +void QVTKWidget::dragEnterEvent(QDragEnterEvent* e) + +{ + + vtkRenderWindowInteractor* iren = NULL; + + if (this->mRenWin) + + { + + iren = this->mRenWin->GetInteractor(); + + } + + + + if (!iren || !iren->GetEnabled()) + + { + + return; + + } + + + + // invoke event and pass qt event for additional data as well + + iren->InvokeEvent(QVTKWidget::DragEnterEvent, e); + +} + + + +void QVTKWidget::dragMoveEvent(QDragMoveEvent* e) + +{ + + vtkRenderWindowInteractor* iren = NULL; + + if (this->mRenWin) + + { + + iren = this->mRenWin->GetInteractor(); + + } + + + + if (!iren || !iren->GetEnabled()) + + { + + return; + + } + + + + // give interactor the event information + + iren->SetEventInformationFlipY(e->pos().x(), e->pos().y()); + + + + // invoke event and pass qt event for additional data as well + + iren->InvokeEvent(QVTKWidget::DragMoveEvent, e); + +} + + + +void QVTKWidget::dragLeaveEvent(QDragLeaveEvent* e) + +{ + + vtkRenderWindowInteractor* iren = NULL; + + if (this->mRenWin) + + { + + iren = this->mRenWin->GetInteractor(); + + } + + + + if (!iren || !iren->GetEnabled()) + + { + + return; + + } + + + + // invoke event and pass qt event for additional data as well + + iren->InvokeEvent(QVTKWidget::DragLeaveEvent, e); + +} + + + +void QVTKWidget::dropEvent(QDropEvent* e) + +{ + + vtkRenderWindowInteractor* iren = NULL; + + if (this->mRenWin) + + { + + iren = this->mRenWin->GetInteractor(); + + } + + + + if (!iren || !iren->GetEnabled()) + + { + + return; + + } + + + + // give interactor the event information + + iren->SetEventInformationFlipY(e->pos().x(), e->pos().y()); + + + + // invoke event and pass qt event for additional data as well + + iren->InvokeEvent(QVTKWidget::DropEvent, e); + +} + + + + + +/*! handle reparenting of widgets + + */ + +#if QT_VERSION < 0x040000 + +void QVTKWidget::reparent(QWidget* parent, Qt::WFlags f, const QPoint& p, bool showit) + +{ + + this->markCachedImageAsDirty(); + + + + if (this->mRenWin) + + { + + // Finalize the window to remove graphics resources associated with + + // this window + + if (this->mRenWin->GetMapped()) + + { + + this->mRenWin->Finalize(); + + } + + + + // have QWidget reparent as normal, but don't show + + QWidget::reparent(parent, f, p, false); + + + + x11_setup_window(); + + + + // connect to new window + +#if defined(Q_WS_MAC) + + static_cast(this->mRenWin)->SetRootWindow( + + reinterpret_cast(this->handle())); + + + +#else + + this->mRenWin->SetWindowId( reinterpret_cast(this->winId())); + +#endif + + + + // start up the window to create graphics resources for this window + + if (isVisible()) + + { + + this->mRenWin->Start(); + + } + + } + + + + // show if requested + + if (showit) + + { + + show(); + + } + +} + +#endif + + + +void QVTKWidget::showEvent(QShowEvent* e) + +{ + + this->markCachedImageAsDirty(); + + + + QWidget::showEvent(e); + +} + + + +QPaintEngine* QVTKWidget::paintEngine() const + +{ + + return NULL; + +} + + + +class QVTKInteractorInternal : public QObject + +{ + +public: + + QVTKInteractorInternal(QObject* p) + + : QObject(p) + + { + + this->SignalMapper = new QSignalMapper(this); + + } + + ~QVTKInteractorInternal() + + { + + } + + QSignalMapper* SignalMapper; + + typedef vtkstd::map TimerMap; + + TimerMap Timers; + +}; + + + + + +/*! allocation method for Qt/VTK interactor + + */ + +vtkStandardNewMacro(QVTKInteractor); + + + +/*! constructor for Qt/VTK interactor + + */ + +QVTKInteractor::QVTKInteractor() + +{ + + this->Internal = new QVTKInteractorInternal(this); + + QObject::connect(this->Internal->SignalMapper, SIGNAL(mapped(int)), this, SLOT(TimerEvent(int)) ); + +} + + + +/*! start method for interactor + + */ + +void QVTKInteractor::Start() + +{ + + vtkErrorMacro(<<"QVTKInteractor cannot control the event loop."); + +} + + + +/*! terminate the application + + */ + +void QVTKInteractor::TerminateApp() + +{ + + // we are in a GUI so let's terminate the GUI the normal way + + //qApp->exit(); + +} + + + + + +/*! handle timer event + + */ + +void QVTKInteractor::TimerEvent(int timerId) + +{ + + if ( !this->GetEnabled() ) + + { + + return; + + } + + this->InvokeEvent(vtkCommand::TimerEvent, (void*)&timerId); + + + + if (this->IsOneShotTimer(timerId)) + + { + + this->DestroyTimer(timerId); // 'cause our Qt timers are always repeating + + } + +} + + + +/*! constructor + + */ + +QVTKInteractor::~QVTKInteractor() + +{ + +} + + + +/*! create Qt timer with an interval of 10 msec. + + */ + +int QVTKInteractor::InternalCreateTimer(int timerId, int vtkNotUsed(timerType), unsigned long duration) + +{ + + QTimer* timer = new QTimer(this); + + timer->start(duration); + + this->Internal->SignalMapper->setMapping(timer, timerId); + + QObject::connect(timer, SIGNAL(timeout()), this->Internal->SignalMapper, SLOT(map())); + + int platformTimerId = timer->timerId(); + + this->Internal->Timers.insert(QVTKInteractorInternal::TimerMap::value_type(platformTimerId, timer)); + + return platformTimerId; + +} + + + +/*! destroy timer + + */ + +int QVTKInteractor::InternalDestroyTimer(int platformTimerId) + +{ + + QVTKInteractorInternal::TimerMap::iterator iter = this->Internal->Timers.find(platformTimerId); + + if (iter != this->Internal->Timers.end()) + + { + + iter->second->stop(); + + delete iter->second; + + this->Internal->Timers.erase(iter); + + return 1; + + } + + return 0; + +} + + + + + +// ***** keysym stuff below ***** + + + +static const char *AsciiToKeySymTable[] = { + + 0, 0, 0, 0, 0, 0, 0, 0, 0, "Tab", 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + "space", "exclam", "quotedbl", "numbersign", + + "dollar", "percent", "ampersand", "quoteright", + + "parenleft", "parenright", "asterisk", "plus", + + "comma", "minus", "period", "slash", + + "0", "1", "2", "3", "4", "5", "6", "7", + + "8", "9", "colon", "semicolon", "less", "equal", "greater", "question", + + "at", "A", "B", "C", "D", "E", "F", "G", + + "H", "I", "J", "K", "L", "M", "N", "O", + + "P", "Q", "R", "S", "T", "U", "V", "W", + + "X", "Y", "Z", "bracketleft", + + "backslash", "bracketright", "asciicircum", "underscore", + + "quoteleft", "a", "b", "c", "d", "e", "f", "g", + + "h", "i", "j", "k", "l", "m", "n", "o", + + "p", "q", "r", "s", "t", "u", "v", "w", + + "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "Delete", + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + + + +const char* ascii_to_key_sym(int i) + +{ + + if (i >= 0) + + { + + return AsciiToKeySymTable[i]; + + } + + return 0; + +} + + + +#define QVTK_HANDLE(x,y) \ + case x : \ + ret = y; \ + break; + + + +const char* qt_key_to_key_sym(Qt::Key i) + +{ + + const char* ret = 0; + + switch (i) + + { + + // Cancel + + QVTK_HANDLE(Qt::Key_Backspace, "BackSpace") + + QVTK_HANDLE(Qt::Key_Tab, "Tab") + +#if QT_VERSION < 0x040000 + + QVTK_HANDLE(Qt::Key_BackTab, "Tab") + +#else + + QVTK_HANDLE(Qt::Key_Backtab, "Tab") + +#endif + + //QVTK_HANDLE(Qt::Key_Clear, "Clear") + + QVTK_HANDLE(Qt::Key_Return, "Return") + + QVTK_HANDLE(Qt::Key_Enter, "Return") + + QVTK_HANDLE(Qt::Key_Shift, "Shift_L") + + QVTK_HANDLE(Qt::Key_Control, "Control_L") + + QVTK_HANDLE(Qt::Key_Alt, "Alt_L") + + QVTK_HANDLE(Qt::Key_Pause, "Pause") + + QVTK_HANDLE(Qt::Key_CapsLock, "Caps_Lock") + + QVTK_HANDLE(Qt::Key_Escape, "Escape") + + QVTK_HANDLE(Qt::Key_Space, "space") + + //QVTK_HANDLE(Qt::Key_Prior, "Prior") + + //QVTK_HANDLE(Qt::Key_Next, "Next") + + QVTK_HANDLE(Qt::Key_End, "End") + + QVTK_HANDLE(Qt::Key_Home, "Home") + + QVTK_HANDLE(Qt::Key_Left, "Left") + + QVTK_HANDLE(Qt::Key_Up, "Up") + + QVTK_HANDLE(Qt::Key_Right, "Right") + + QVTK_HANDLE(Qt::Key_Down, "Down") + + + + // Select + + // Execute + + QVTK_HANDLE(Qt::Key_SysReq, "Snapshot") + + QVTK_HANDLE(Qt::Key_Insert, "Insert") + + QVTK_HANDLE(Qt::Key_Delete, "Delete") + + QVTK_HANDLE(Qt::Key_Help, "Help") + + QVTK_HANDLE(Qt::Key_0, "0") + + QVTK_HANDLE(Qt::Key_1, "1") + + QVTK_HANDLE(Qt::Key_2, "2") + + QVTK_HANDLE(Qt::Key_3, "3") + + QVTK_HANDLE(Qt::Key_4, "4") + + QVTK_HANDLE(Qt::Key_5, "5") + + QVTK_HANDLE(Qt::Key_6, "6") + + QVTK_HANDLE(Qt::Key_7, "7") + + QVTK_HANDLE(Qt::Key_8, "8") + + QVTK_HANDLE(Qt::Key_9, "9") + + QVTK_HANDLE(Qt::Key_A, "a") + + QVTK_HANDLE(Qt::Key_B, "b") + + QVTK_HANDLE(Qt::Key_C, "c") + + QVTK_HANDLE(Qt::Key_D, "d") + + QVTK_HANDLE(Qt::Key_E, "e") + + QVTK_HANDLE(Qt::Key_F, "f") + + QVTK_HANDLE(Qt::Key_G, "g") + + QVTK_HANDLE(Qt::Key_H, "h") + + QVTK_HANDLE(Qt::Key_I, "i") + + QVTK_HANDLE(Qt::Key_J, "h") + + QVTK_HANDLE(Qt::Key_K, "k") + + QVTK_HANDLE(Qt::Key_L, "l") + + QVTK_HANDLE(Qt::Key_M, "m") + + QVTK_HANDLE(Qt::Key_N, "n") + + QVTK_HANDLE(Qt::Key_O, "o") + + QVTK_HANDLE(Qt::Key_P, "p") + + QVTK_HANDLE(Qt::Key_Q, "q") + + QVTK_HANDLE(Qt::Key_R, "r") + + QVTK_HANDLE(Qt::Key_S, "s") + + QVTK_HANDLE(Qt::Key_T, "t") + + QVTK_HANDLE(Qt::Key_U, "u") + + QVTK_HANDLE(Qt::Key_V, "v") + + QVTK_HANDLE(Qt::Key_W, "w") + + QVTK_HANDLE(Qt::Key_X, "x") + + QVTK_HANDLE(Qt::Key_Y, "y") + + QVTK_HANDLE(Qt::Key_Z, "z") + + // KP_0 - KP_9 + + QVTK_HANDLE(Qt::Key_Asterisk, "asterisk") + + QVTK_HANDLE(Qt::Key_Plus, "plus") + + // bar + + QVTK_HANDLE(Qt::Key_Minus, "minus") + + QVTK_HANDLE(Qt::Key_Period, "period") + + QVTK_HANDLE(Qt::Key_Slash, "slash") + + QVTK_HANDLE(Qt::Key_F1, "F1") + + QVTK_HANDLE(Qt::Key_F2, "F2") + + QVTK_HANDLE(Qt::Key_F3, "F3") + + QVTK_HANDLE(Qt::Key_F4, "F4") + + QVTK_HANDLE(Qt::Key_F5, "F5") + + QVTK_HANDLE(Qt::Key_F6, "F6") + + QVTK_HANDLE(Qt::Key_F7, "F7") + + QVTK_HANDLE(Qt::Key_F8, "F8") + + QVTK_HANDLE(Qt::Key_F9, "F9") + + QVTK_HANDLE(Qt::Key_F10, "F10") + + QVTK_HANDLE(Qt::Key_F11, "F11") + + QVTK_HANDLE(Qt::Key_F12, "F12") + + QVTK_HANDLE(Qt::Key_F13, "F13") + + QVTK_HANDLE(Qt::Key_F14, "F14") + + QVTK_HANDLE(Qt::Key_F15, "F15") + + QVTK_HANDLE(Qt::Key_F16, "F16") + + QVTK_HANDLE(Qt::Key_F17, "F17") + + QVTK_HANDLE(Qt::Key_F18, "F18") + + QVTK_HANDLE(Qt::Key_F19, "F19") + + QVTK_HANDLE(Qt::Key_F20, "F20") + + QVTK_HANDLE(Qt::Key_F21, "F21") + + QVTK_HANDLE(Qt::Key_F22, "F22") + + QVTK_HANDLE(Qt::Key_F23, "F23") + + QVTK_HANDLE(Qt::Key_F24, "F24") + + QVTK_HANDLE(Qt::Key_NumLock, "Num_Lock") + + QVTK_HANDLE(Qt::Key_ScrollLock, "Scroll_Lock") + + + + default: + + break; + + } + + return ret; + +} + + + + + + + + + +// X11 stuff near the bottom of the file + +// to prevent namespace collisions with Qt headers + + + +#if defined Q_WS_X11 + +#if defined(VTK_USE_OPENGL_LIBRARY) + +#include "vtkXOpenGLRenderWindow.h" + +#endif + +#ifdef VTK_USE_MANGLED_MESA + +#include "vtkXMesaRenderWindow.h" + +#endif + +#endif + + + + + +void QVTKWidget::x11_setup_window() + +{ + +#if defined Q_WS_X11 + + + + // this whole function is to allow this window to have a + + // different colormap and visual than the rest of the Qt application + + // this is very important if Qt's default visual and colormap is + + // not enough to get a decent graphics window + + + + + + // save widget states + + bool tracking = this->hasMouseTracking(); + +#if QT_VERSION < 0x040000 + + FocusPolicy focus_policy = focusPolicy(); + +#else + + Qt::FocusPolicy focus_policy = focusPolicy(); + +#endif + + bool visible = isVisible(); + + if (visible) + + { + + hide(); + + } + + + + + + // get visual and colormap from VTK + + XVisualInfo* vi = 0; + + Colormap cmap = 0; + + Display* display = reinterpret_cast(mRenWin->GetGenericDisplayId()); + + + + // check ogl and mesa and get information we need to create a decent window + +#if defined(VTK_USE_OPENGL_LIBRARY) + + vtkXOpenGLRenderWindow* ogl_win = vtkXOpenGLRenderWindow::SafeDownCast(mRenWin); + + if (ogl_win) + + { + + vi = ogl_win->GetDesiredVisualInfo(); + + cmap = ogl_win->GetDesiredColormap(); + + } + +#endif + +#ifdef VTK_USE_MANGLED_MESA + + if (!vi) + + { + + vtkXMesaRenderWindow* mgl_win = vtkXMesaRenderWindow::SafeDownCast(mRenWin); + + if (mgl_win) + + { + + vi = mgl_win->GetDesiredVisualInfo(); + + cmap = mgl_win->GetDesiredColormap(); + + } + + } + +#endif + + + + // can't get visual, oh well. + + // continue with Qt's default visual as it usually works + + if (!vi) + + { + + if (visible) + + { + + show(); + + } + + return; + + } + + + + // create the X window based on information VTK gave us + + XSetWindowAttributes attrib; + + attrib.colormap = cmap; + + attrib.border_pixel = BlackPixel(display, DefaultScreen(display)); + + + + Window p = RootWindow(display, DefaultScreen(display)); + + if (parentWidget()) + + { + + p = parentWidget()->winId(); + + } + + + + XWindowAttributes a; + + XGetWindowAttributes(display, this->winId(), &a); + + + + Window win = XCreateWindow(display, p, a.x, a.y, a.width, a.height, + + 0, vi->depth, InputOutput, vi->visual, + + CWBorderPixel|CWColormap, &attrib); + + + + // backup colormap stuff + + Window *cmw; + + Window *cmwret; + + int count; + + if ( XGetWMColormapWindows(display, topLevelWidget()->winId(), &cmwret, &count) ) + + { + + cmw = new Window[count+1]; + + memcpy( (char *)cmw, (char *)cmwret, sizeof(Window)*count ); + + XFree( (char *)cmwret ); + + int i; + + for ( i=0; i= count ) + + { + + cmw[count++] = win; + + } + + } + + else + + { + + count = 1; + + cmw = new Window[count]; + + cmw[0] = win; + + } + + + + + + // tell Qt to initialize anything it needs to for this window + + create(win); + + + + // restore colormaps + + XSetWMColormapWindows( display, topLevelWidget()->winId(), cmw, count ); + + + + delete [] cmw; + + + + XFlush(display); + + + + // restore widget states + + this->setMouseTracking(tracking); + +#if QT_VERSION < 0x040000 + + this->setBackgroundMode( Qt::NoBackground ); + +#else + + this->setAttribute(Qt::WA_NoBackground); + + this->setAttribute(Qt::WA_PaintOnScreen); + +#endif + + this->setFocusPolicy(focus_policy); + + if (visible) + + { + + show(); + + } + + + +#endif + +} + + + +#if defined (Q_WS_MAC) && QT_VERSION >= 0x040000 + +OSStatus QVTKWidget::DirtyRegionProcessor(EventHandlerCallRef, EventRef event, void* wid) + +{ + + QVTKWidget* widget = reinterpret_cast(wid); + + UInt32 event_kind = GetEventKind(event); + + UInt32 event_class = GetEventClass(event); + + if (event_class == 'cute' && event_kind == 20) + + { + + static_cast(widget->GetRenderWindow())->UpdateGLRegion(); + + } + + return eventNotHandledErr; + +} + + + +#endif + + + +#if defined (Q_WS_MAC) && QT_VERSION < 0x040000 + + + +// gotta do some special stuff on the MAC to make it work right + +// this stuff will need changing when using Qt4 with HIViews + + + +#include + + + +void QVTKWidget::macFixRect() + +{ + + AGLContext context = static_cast(this->GetRenderWindow())->GetContextId(); + + + + if (!this->isTopLevel()) + + { + + GLint bufRect[4]; + + + + // always do AGL_BUFFER_RECT if we have a parent + + if (!aglIsEnabled(context, AGL_BUFFER_RECT)) + + aglEnable(context, AGL_BUFFER_RECT); + + + + // get the clip region + + QRegion clip = this->clippedRegion(); + + QRect clip_rect = clip.boundingRect(); + + + + // get the position of this widget with respect to the top level widget + + QPoint mp(posInWindow(this)); + + int win_height = this->topLevelWidget()->height(); + + win_height -= win_height - this->topLevelWidget()->clippedRegion(FALSE).boundingRect().height(); + + + + // give the position and size to agl + + bufRect[0] = mp.x(); + + bufRect[1] = win_height -(mp.y() + this->height()); + + bufRect[2] = this->width(); + + bufRect[3] = this->height(); + + aglSetInteger(context, AGL_BUFFER_RECT, bufRect); + + + + if (clip_rect.isEmpty()) + + { + + // no clipping, disable it + + if (!aglIsEnabled(context, AGL_CLIP_REGION)) + + aglDisable(context, AGL_CLIP_REGION); + + + + bufRect[0] = 0; + + bufRect[1] = 0; + + bufRect[2] = 0; + + bufRect[3] = 0; + + aglSetInteger(context, AGL_BUFFER_RECT, bufRect); + + } + + else + + { + + // we are clipping, so lets enable it + + if (!aglIsEnabled(context, AGL_CLIP_REGION)) + + aglEnable(context, AGL_CLIP_REGION); + + + + // give agl the clip region + + aglSetInteger(context, AGL_CLIP_REGION, (const GLint*)clip.handle(TRUE)); + + } + + } + + + + // update the context + + aglUpdateContext(context); + +} + + + +void QVTKWidget::setRegionDirty(bool b) + +{ + + // the region is dirty and needs redrawn, but not yet + + // signal that it needs to be done when it is possible + + QWidget::setRegionDirty(b); + + QTimer::singleShot(1, this, SLOT(internalMacFixRect())); + + + +} + + + +void QVTKWidget::macWidgetChangedWindow() + +{ + + macFixRect(); + +} + +#endif + + + +// slot to update the draw region and draw the scene + +void QVTKWidget::internalMacFixRect() + +{ + +#if defined(Q_WS_MAC) && QT_VERSION < 0x040000 + + this->macFixRect(); + + this->update(); + +#endif + +} + + + +static void dirty_cache(vtkObject *caller, unsigned long, + + void *clientdata, void *) + +{ + + QVTKWidget *widget = reinterpret_cast(clientdata); + + widget->markCachedImageAsDirty(); + + + + vtkRenderWindow *renwin = vtkRenderWindow::SafeDownCast(caller); + + if (renwin) + + { + + if ( widget->isAutomaticImageCacheEnabled() + + && ( renwin->GetDesiredUpdateRate() + + < widget->maxRenderRateForImageCache() ) ) + + { + + widget->saveImageToCache(); + + } + + } + +} + + + diff --git a/vv/QVTKWidget.h b/vv/QVTKWidget.h new file mode 100644 index 0000000..ef91121 --- /dev/null +++ b/vv/QVTKWidget.h @@ -0,0 +1,310 @@ +/*========================================================================= + + Copyright 2004 Sandia Corporation. + Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + license for use of this work by or on behalf of the + U.S. Government. Redistribution and use in source and binary forms, with + or without modification, are permitted provided that this Notice and any + statement of authorship are reproduced on all copies. + +=========================================================================*/ + +/*======================================================================== + For general information about using VTK and Qt, see: + http://www.trolltech.com/products/3rdparty/vtksupport.html +=========================================================================*/ + +/*======================================================================== + !!! WARNING for those who want to contribute code to this file. + !!! If you use a commercial edition of Qt, you can modify this code. + !!! If you use an open source version of Qt, you are free to modify + !!! and use this code within the guidelines of the GPL license. + !!! Unfortunately, you cannot contribute the changes back into this + !!! file. Doing so creates a conflict between the GPL and BSD-like VTK + !!! license. +=========================================================================*/ + +// .NAME QVTKWidget - Display a vtkRenderWindow in a Qt's QWidget. +// .SECTION Description +// QVTKWidget provides a way to display VTK data in a Qt widget. + +#ifndef Q_VTK_WIDGET_H +#define Q_VTK_WIDGET_H + +#include +class QPaintEngine; + +class vtkRenderWindow; +class QVTKInteractor; +#include +#include +#include +class vtkUnsignedCharArray; + +#if defined(Q_WS_MAC) && QT_VERSION >= 0x040000 +#include // Event handling for dirty region +#endif + +#if defined(WIN32) && defined(VTK_BUILD_SHARED_LIBS) +#if defined(QVTK_EXPORTS) || defined(QVTKWidgetPlugin_EXPORTS) +#define QVTK_EXPORT __declspec( dllexport ) +#else +#define QVTK_EXPORT __declspec( dllimport ) +#endif +#define QVTK_EXPORT +#else +#define QVTK_EXPORT +#endif + +//! QVTKWidget displays a VTK window in a Qt window. +class QVTK_EXPORT QVTKWidget : public QWidget +{ + Q_OBJECT + + Q_PROPERTY(bool automaticImageCacheEnabled + READ isAutomaticImageCacheEnabled + WRITE setAutomaticImageCacheEnabled) + Q_PROPERTY(double maxRenderRateForImageCache + READ maxRenderRateForImageCache + WRITE setMaxRenderRateForImageCache) + Q_PROPERTY(QString text READ text WRITE setText) + +public: +#if QT_VERSION < 0x040000 + //! constructor for Qt 3 + QVTKWidget(QWidget* parent = NULL, const char* name = NULL, Qt::WFlags f = 0); +#else + //! constructor for Qt 4 + QVTKWidget(QWidget* parent = NULL, Qt::WFlags f = 0); +#endif + + QString text() const { + return ""; + } + + //! destructor + virtual ~QVTKWidget(); + + // Description: + // Set the vtk render window, if you wish to use your own vtkRenderWindow + virtual void SetRenderWindow(vtkRenderWindow*); + + // Description: + // Get the vtk render window. + virtual vtkRenderWindow* GetRenderWindow(); + + // Description: + // Get the Qt/vtk interactor that was either created by default or set by the user + virtual QVTKInteractor* GetInteractor(); + + // Description: + // Enum for additional event types supported. + // These events can be picked up by command observers on the interactor + enum vtkCustomEvents + { + ContextMenuEvent = vtkCommand::UserEvent + 100, + DragEnterEvent, + DragMoveEvent, + DragLeaveEvent, + DropEvent + }; + + // Description: + // Enables/disables automatic image caching. If disabled (the default), + // QVTKWidget will not call saveImageToCache() on its own. + virtual void setAutomaticImageCacheEnabled(bool flag); + virtual bool isAutomaticImageCacheEnabled() const; + + // Description: + // If automatic image caching is enabled, then the image will be cached + // after every render with a DesiredUpdateRate that is greater than + // this parameter. By default, the vtkRenderWindowInteractor will + // change the desired render rate depending on the user's + // interactions. (See vtkRenderWindow::DesiredUpdateRate, + // vtkRenderWindowInteractor::DesiredUpdateRate and + // vtkRenderWindowInteractor::StillUpdateRate for more details.) + virtual void setMaxRenderRateForImageCache(double rate); + virtual double maxRenderRateForImageCache() const; + + // Description: + // Returns the current image in the window. If the image cache is up + // to date, that is returned to avoid grabbing other windows. + virtual vtkUnsignedCharArray* cachedImage(); + +#if QT_VERSION < 0x040000 + // Description: + // Handle reparenting of this widget in Qt 3.x + virtual void reparent(QWidget* parent, Qt::WFlags f, const QPoint& p, bool showit); +#endif + + // Description: + // Handle showing of the Widget + virtual void showEvent(QShowEvent*); + + virtual QPaintEngine* paintEngine() const; + +signals: + // Description: + // This signal will be emitted whenever a mouse event occurs + // within the QVTK window + void mouseEvent(QMouseEvent* event); + + // Description: + // This signal will be emitted whenever the cached image goes from clean + // to dirty. + void cachedImageDirty(); + + // Description: + // This signal will be emitted whenever the cached image is refreshed. + void cachedImageClean(); + +public slots: + // Description: + // This will mark the cached image as dirty. This slot is automatically + // invoked whenever the render window has a render event or the widget is + // resized. Your application should invoke this slot whenever the image in + // the render window is changed by some other means. If the image goes + // from clean to dirty, the cachedImageDirty() signal is emitted. + void markCachedImageAsDirty(); + + // Description: + // If the cached image is dirty, it is updated with the current image in + // the render window and the cachedImageClean() signal is emitted. + void saveImageToCache(); + + void setText(const QString &) {}; + +protected: + // overloaded resize handler + virtual void resizeEvent(QResizeEvent* event); + // overloaded move handler + virtual void moveEvent(QMoveEvent* event); + // overloaded paint handler + virtual void paintEvent(QPaintEvent* event); + + // overloaded mouse press handler + virtual void mousePressEvent(QMouseEvent* event); + // overloaded mouse move handler + virtual void mouseMoveEvent(QMouseEvent* event); + // overloaded mouse release handler + virtual void mouseReleaseEvent(QMouseEvent* event); + // overloaded key press handler + virtual void keyPressEvent(QKeyEvent* event); + // overloaded key release handler + virtual void keyReleaseEvent(QKeyEvent* event); + // overloaded enter event + virtual void enterEvent(QEvent*); + // overloaded leave event + virtual void leaveEvent(QEvent*); +#ifndef QT_NO_WHEELEVENT + // overload wheel mouse event + virtual void wheelEvent(QWheelEvent*); +#endif + // overload focus event + virtual void focusInEvent(QFocusEvent*); + // overload focus event + virtual void focusOutEvent(QFocusEvent*); + // overload Qt's event() to capture more keys + bool event( QEvent* e ); + + // overload context menu event + virtual void contextMenuEvent(QContextMenuEvent*); + // overload drag enter event + virtual void dragEnterEvent(QDragEnterEvent*); + // overload drag move event + virtual void dragMoveEvent(QDragMoveEvent*); + // overload drag leave event + virtual void dragLeaveEvent(QDragLeaveEvent*); + // overload drop event + virtual void dropEvent(QDropEvent*); + + // the vtk render window + vtkRenderWindow* mRenWin; + + // set up an X11 window based on a visual and colormap + // that VTK chooses + void x11_setup_window(); + +#if defined(Q_WS_MAC) && QT_VERSION < 0x040000 + void macFixRect(); + virtual void setRegionDirty(bool); + virtual void macWidgetChangedWindow(); +#endif + +#if defined(Q_WS_MAC) && QT_VERSION >= 0x040000 + EventHandlerUPP DirtyRegionHandlerUPP; + EventHandlerRef DirtyRegionHandler; + static OSStatus DirtyRegionProcessor(EventHandlerCallRef er, EventRef event, void*); +#endif + +private slots: + void internalMacFixRect(); + +protected: + + vtkUnsignedCharArray* mCachedImage; + bool cachedImageCleanFlag; + bool automaticImageCache; + double maxImageCacheRenderRate; + +private: + //! unimplemented operator= + QVTKWidget const& operator=(QVTKWidget const&); + //! unimplemented copy + QVTKWidget(const QVTKWidget&); + +}; + +class QVTKInteractorInternal; + +// .NAME QVTKInteractor - An interactor for the QVTKWidget. +// .SECTION Description +// QVTKInteractor is an interactor for a QVTKWiget. + +class QVTK_EXPORT QVTKInteractor : public QObject, public vtkRenderWindowInteractor +{ + Q_OBJECT +public: + static QVTKInteractor* New(); + vtkTypeMacro(QVTKInteractor,vtkRenderWindowInteractor); + + // Description: + // Overloaded terminiate app, which does nothing in Qt. + // Use qApp->exit() instead. + virtual void TerminateApp(); + + // Description: + // Overloaded start method does nothing. + // Use qApp->exec() instead. + virtual void Start(); + +public slots: +// timer event slot + virtual void TimerEvent(int timerId); + +protected: + // constructor + QVTKInteractor(); + // destructor + ~QVTKInteractor(); + + // create a Qt Timer + virtual int InternalCreateTimer(int timerId, int timerType, unsigned long duration); + // destroy a Qt Timer + virtual int InternalDestroyTimer(int platformTimerId); + +private: + + QVTKInteractorInternal* Internal; + + // unimplemented copy + QVTKInteractor(const QVTKInteractor&); + // unimplemented operator= + void operator=(const QVTKInteractor&); + +}; + + +#endif + + diff --git a/vv/ReadMe.txt b/vv/ReadMe.txt new file mode 100644 index 0000000..081302a --- /dev/null +++ b/vv/ReadMe.txt @@ -0,0 +1,66 @@ +How to install and run vv on linux: + +1.CMake : +Before doing anything, you need to download the latest stable release of CMake : + http://www.cmake.org/HTML/Index.html + +Uncompress the file and add cmake to your path : + tar zxvf cmake-2.4.2-Linux-i386.tar.gz + tar xvf cmake-2.4.2-Linux-files.tar + PATH=$PATH:/cmake/bin/directory + +2.ITK: +Download the latest stable release from their page or from their CVS repository : + http://www.itk.org/HTML/Download.htm + +Uncompress it and rename the resulting folder as « Insight » : + tar zxvf InsightToolkit-2.6.0.tar.gz + mkdir Insight + mv InsightToolkit-2.6.0 Insight + +Still from your home, create a binary directory, get into it and run CMake : + mkdir Insight-binary + cd Insight-binary + ccmake ../Insight + +NB : You can disable BUILT_EXAMPLES and BUILT_TESTS. + +Then compile ITK: + make + +3.Qt 4: +Download the latest stable release from their page : + http://trolltech.com/downloads/opensource + +Install it following instructions on : + http://doc.trolltech.com/4.3/install-x11.html + +4.VTK: + +Download the latest stable release from their CVS repository : + http://www.vtk.org/get-software.php + +Create a binary directory, get into it and run CMake : + mkdir vtk-binary + cd vtk-binary + ccmake ../vtk + +NB: you need to change built options to make it compatible with Qt. + Set BUILD_SHARED_LIBS to ON, + Set VTK_USE_GUISUPPORT to ON + Set VTK_USE_QVTK to ON. Then, specify the Qt version you are using. + +Then compile vtk : + make + +5.vv: + +Download the latest release from the git repository : + git clone http://creatis.insa-lyon.fr/~schaerer/vv.git + +Go inside the build directory: + cd vv/build + +run cmake and compile it. + ccmake .. + make -j2 diff --git a/vv/icons/GPSup.png b/vv/icons/GPSup.png new file mode 100644 index 0000000..27e98ce Binary files /dev/null and b/vv/icons/GPSup.png differ diff --git a/vv/icons/NEgrid.png b/vv/icons/NEgrid.png new file mode 100644 index 0000000..33853a5 Binary files /dev/null and b/vv/icons/NEgrid.png differ diff --git a/vv/icons/NOgrid.png b/vv/icons/NOgrid.png new file mode 100644 index 0000000..0eaf14b Binary files /dev/null and b/vv/icons/NOgrid.png differ diff --git a/vv/icons/SEgrid.png b/vv/icons/SEgrid.png new file mode 100644 index 0000000..aa61aff Binary files /dev/null and b/vv/icons/SEgrid.png differ diff --git a/vv/icons/SOgrid.png b/vv/icons/SOgrid.png new file mode 100644 index 0000000..7bb80a3 Binary files /dev/null and b/vv/icons/SOgrid.png differ diff --git a/vv/icons/adjustsize.png b/vv/icons/adjustsize.png new file mode 100644 index 0000000..c4d884c Binary files /dev/null and b/vv/icons/adjustsize.png differ diff --git a/vv/icons/crop.png b/vv/icons/crop.png new file mode 100644 index 0000000..3558379 Binary files /dev/null and b/vv/icons/crop.png differ diff --git a/vv/icons/cross.png b/vv/icons/cross.png new file mode 100644 index 0000000..b243163 Binary files /dev/null and b/vv/icons/cross.png differ diff --git a/vv/icons/cursor-uparrow.png b/vv/icons/cursor-uparrow.png new file mode 100644 index 0000000..dca68e4 Binary files /dev/null and b/vv/icons/cursor-uparrow.png differ diff --git a/vv/icons/cut.png b/vv/icons/cut.png new file mode 100644 index 0000000..54638e9 Binary files /dev/null and b/vv/icons/cut.png differ diff --git a/vv/icons/ducky.bmp b/vv/icons/ducky.bmp new file mode 100755 index 0000000..00c1d20 Binary files /dev/null and b/vv/icons/ducky.bmp differ diff --git a/vv/icons/ducky.ico b/vv/icons/ducky.ico new file mode 100755 index 0000000..359c4b9 Binary files /dev/null and b/vv/icons/ducky.ico differ diff --git a/vv/icons/ducky.png b/vv/icons/ducky.png new file mode 100644 index 0000000..d33064f Binary files /dev/null and b/vv/icons/ducky.png differ diff --git a/vv/icons/editgrid.png b/vv/icons/editgrid.png new file mode 100644 index 0000000..bba4a69 Binary files /dev/null and b/vv/icons/editgrid.png differ diff --git a/vv/icons/exit.png b/vv/icons/exit.png new file mode 100644 index 0000000..539cb2e Binary files /dev/null and b/vv/icons/exit.png differ diff --git a/vv/icons/fileopen.png b/vv/icons/fileopen.png new file mode 100644 index 0000000..fc6f17e Binary files /dev/null and b/vv/icons/fileopen.png differ diff --git a/vv/icons/filesave.png b/vv/icons/filesave.png new file mode 100644 index 0000000..8feec99 Binary files /dev/null and b/vv/icons/filesave.png differ diff --git a/vv/icons/fusion.png b/vv/icons/fusion.png new file mode 100644 index 0000000..7e0779e Binary files /dev/null and b/vv/icons/fusion.png differ diff --git a/vv/icons/invertcolor.png b/vv/icons/invertcolor.png new file mode 100644 index 0000000..e65caf6 Binary files /dev/null and b/vv/icons/invertcolor.png differ diff --git a/vv/icons/open.png b/vv/icons/open.png new file mode 100644 index 0000000..45fa288 Binary files /dev/null and b/vv/icons/open.png differ diff --git a/vv/icons/player_pause.png b/vv/icons/player_pause.png new file mode 100644 index 0000000..8c9bcc4 Binary files /dev/null and b/vv/icons/player_pause.png differ diff --git a/vv/icons/player_play.png b/vv/icons/player_play.png new file mode 100644 index 0000000..70daa33 Binary files /dev/null and b/vv/icons/player_play.png differ diff --git a/vv/icons/player_stop.png b/vv/icons/player_stop.png new file mode 100644 index 0000000..ce6585a Binary files /dev/null and b/vv/icons/player_stop.png differ diff --git a/vv/icons/rotateright.png b/vv/icons/rotateright.png new file mode 100644 index 0000000..ec5e866 Binary files /dev/null and b/vv/icons/rotateright.png differ diff --git a/vv/icons/splashscreen.PNG b/vv/icons/splashscreen.PNG new file mode 100755 index 0000000..9b33e5b Binary files /dev/null and b/vv/icons/splashscreen.PNG differ diff --git a/vv/icons/splashscreen.odp b/vv/icons/splashscreen.odp new file mode 100644 index 0000000..7cd3ca5 Binary files /dev/null and b/vv/icons/splashscreen.odp differ diff --git a/vv/icons/splashscreen.ppt b/vv/icons/splashscreen.ppt new file mode 100755 index 0000000..4bc508d Binary files /dev/null and b/vv/icons/splashscreen.ppt differ diff --git a/vv/icons/splashscreen2.png b/vv/icons/splashscreen2.png new file mode 100644 index 0000000..a604746 Binary files /dev/null and b/vv/icons/splashscreen2.png differ diff --git a/vv/icons/standardbutton-apply-16.png b/vv/icons/standardbutton-apply-16.png new file mode 100644 index 0000000..8f11ce6 Binary files /dev/null and b/vv/icons/standardbutton-apply-16.png differ diff --git a/vv/icons/standardbutton-cancel-16.png b/vv/icons/standardbutton-cancel-16.png new file mode 100644 index 0000000..7bd25bd Binary files /dev/null and b/vv/icons/standardbutton-cancel-16.png differ diff --git a/vv/icons/undo.png b/vv/icons/undo.png new file mode 100644 index 0000000..8cf63a8 Binary files /dev/null and b/vv/icons/undo.png differ diff --git a/vv/make_vv_class.sh b/vv/make_vv_class.sh new file mode 100755 index 0000000..658c94b --- /dev/null +++ b/vv/make_vv_class.sh @@ -0,0 +1,15 @@ +#!/bin/bash +if [ -z "$1" ] +then + echo "Usage: make_vv_class.sh classname" + exit 1 +fi +if [ -e vv"$1".cxx ] +then + echo "Error: vv$1.cxx already exists classname" + exit 1 +fi + +cp vvTemplateFile.cxx vv$1.cxx +cp vvTemplateFile.h vv$1.h +sed -i "s/XXX/$1/g" vv$1.* diff --git a/vv/nkitkXDRImageIO.h b/vv/nkitkXDRImageIO.h new file mode 100644 index 0000000..6d7279b --- /dev/null +++ b/vv/nkitkXDRImageIO.h @@ -0,0 +1,75 @@ +#ifndef NKITKXDRIMAGEIO_H +#define NKITKXDRIMAGEIO_H + +/** + * @file nkitkXDRImageIO.h + * @author Simon Rit + * @date Sun Jun 1 22:07:45 2008 + * + * @brief + * + * + */ + +// itk include +#include "itkImageIOBase.h" + +namespace nkitk { + +//==================================================================== +// Class for reading XDR Image file format +class XDRImageIO: public itk::ImageIOBase +{ +public: + /** Standard class typedefs. */ + typedef XDRImageIO Self; + typedef itk::ImageIOBase Superclass; + typedef itk::SmartPointer Pointer; + typedef signed short int PixelType; + typedef enum {UNIFORM,RECTILINEAR,IRREGULAR} AVSType; + + XDRImageIO():Superclass() { + forcenoswap = 0; + } + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(XDRImageIO, ImageIOBase); + + /*-------- This part of the interface deals with reading data. ------ */ + virtual int ReadImageInformationWithError(); + virtual int ReadWithError(void * buffer); + virtual void ReadImageInformation(); + virtual void Read(void * buffer); + virtual bool CanReadFile( const char* FileNameToRead ); + + /*-------- This part of the interfaces deals with writing data. ----- */ + virtual void WriteImageInformation(bool keepOfStream) { + ; + } + virtual void WriteImageInformation() { + WriteImageInformation(false); + } + virtual bool CanWriteFile(const char* filename) { + return false; + } + virtual void Write(const void* buffer) { + ; + } + +protected: + void ITKError(std::string funcName, int msgID); + + int m_HeaderSize; + int forcenoswap; +}; // end class XDRImageIO + +} // end namespace + +// explicit template instantiation +template class itk::CreateObjectFunction; + +#endif /* end #define NKITKXDRIMAGEIO_H */ + diff --git a/vv/nkitkXDRImageIOFactory.cxx b/vv/nkitkXDRImageIOFactory.cxx new file mode 100644 index 0000000..725e267 --- /dev/null +++ b/vv/nkitkXDRImageIOFactory.cxx @@ -0,0 +1,28 @@ +#ifndef NKITKXDRIMAGEIOFACTORY_CXX +#define NKITKXDRIMAGEIOFACTORY_CXX + +/** + * @file nkitkXDRImageIOFactory.cxx + * @author Simon Rit + * @date Sun Jun 1 22:11:20 2008 + * + * @brief + * + * + */ + +#include "nkitkXDRImageIOFactory.h" + +//==================================================================== +nkitk::XDRImageIOFactory::XDRImageIOFactory() +{ + this->RegisterOverride("itkImageIOBase", + "XDRImageIO", + "XDR Image IO", + 1, + itk::CreateObjectFunction::New()); +} + + +#endif /* end #define NKITKXDRIMAGEIOFACTORY_CXX */ + diff --git a/vv/nkitkXDRImageIOFactory.h b/vv/nkitkXDRImageIOFactory.h new file mode 100644 index 0000000..1c135b4 --- /dev/null +++ b/vv/nkitkXDRImageIOFactory.h @@ -0,0 +1,69 @@ +#ifndef NKITKXDRIMAGEIOFACTORY_H +#define NKITKXDRIMAGEIOFACTORY_H + +/** + * @file nkitkXDRImageIOFactory.h + * @author Simon Rit + * @date Sun Jun 1 22:09:56 2008 + * + * @brief + * + * + */ + +// nkitk include +#include "nkitkXDRImageIO.h" + +// itk include +#include "itkImageIOBase.h" +#include "itkObjectFactoryBase.h" +#include "itkVersion.h" + +namespace nkitk { + +//==================================================================== +// Factory for reading XDR Image file format +class XDRImageIOFactory: public itk::ObjectFactoryBase +{ +public: + /** Standard class typedefs. */ + typedef XDRImageIOFactory Self; + typedef itk::ObjectFactoryBase Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Class methods used to interface with the registered factories. */ + const char* GetITKSourceVersion(void) const { + return ITK_SOURCE_VERSION; + } + + const char* GetDescription(void) const { + return "XDR ImageIO Factory, allows the loading of XDR images into insight"; + } + + /** Method for class instantiation. */ + itkFactorylessNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(XDRImageIOFactory, ObjectFactoryBase); + + /** Register one factory of this type */ + static void RegisterOneFactory(void) { + ObjectFactoryBase::RegisterFactory( Self::New() ); + } + +protected: + XDRImageIOFactory(); + ~XDRImageIOFactory() {}; + typedef XDRImageIOFactory myProductType; + const myProductType* m_MyProduct; + +private: + XDRImageIOFactory(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented +}; + +} // end namespace + +#endif /* end #define NKITKXDRIMAGEIOFACTORY_H */ + diff --git a/vv/nkitkXDRImageIOReader.cxx b/vv/nkitkXDRImageIOReader.cxx new file mode 100644 index 0000000..f24ab5a --- /dev/null +++ b/vv/nkitkXDRImageIOReader.cxx @@ -0,0 +1,1676 @@ +#ifndef NKITKXDRIMAGEIO_CXX +#define NKITKXDRIMAGEIO_CXX + +/** + * @file nkitkXDRImageIO.cxx + * @author Simon Rit + * @date Sun Jun 1 22:12:20 2008 + * + * @brief + * + * + */ + +#include "nkitkXDRImageIO.h" + +// std include +#include +#include +#include + +//defines +#define MAXDIM 5 +#define AVSerror(v) std::cerr << "Error in nkitk::XDRImageIO. Message:" << v << std::endl; +#ifdef _WIN32 +#ifdef memicmp +#undef memicmp +#endif +#define memicmp _memicmp +#else +#define memicmp strncasecmp +#endif + +/************************************************************************/ +/* */ +/* file : AVS_RXDR.CPP */ +/* */ +/* purpose : AVS module for reading XDRs */ +/* */ +/* authors : Lambert Zijp (Conquest) */ +/* Based on a true story by Marcel van Herk */ +/* */ +/* date : 19980528 */ +/* */ +/* portability: AVS requires sizeof(void *)==sizeof(int) */ +/* This module assumes sizeof(int)>=4 */ +/* */ +/* notes : */ +/* */ +/* */ +/************************************************************************/ +/* Updates: +When Who What +19980528 ljz Copied from mbfield1 +19981209 mvh Taken into action by removing _; added READ_XDR_HEADER +19981210 mvh+lsp Now proper freeing of buff in case of error +19990130 mvh Added ENUM_XDR_HEADER +19990206 mvh Added READ_XDR_PREVIEW +19990208 mvh Fixed this, the while(1) fgets loop is rquired to skip long headers +19990406 ljz Removed sizelimit of dimensions +19991003 mvh Loosened sizelimit for veclen to 1000 +19991005 mvh Remove spaces from AVS own header lines (ndim etc) in scan_header +20000808 lsp No longer mix file streams and handles +20000821 ljz Reader can now handle NkiCompression +20000822 lsp+nd Initialize data and datasize for dots, added "const" to avoid + writing into a literal string +20000823 mvh Optimized nki_private_decompression mode 2 (from 6.4 to 4.9 s) + reading mode 1: compression makes read faster + reading mode 2: read compressed at same speed as uncompressed +20000824 mvh Speed up mode 2 to 4.2 s: only check compressedCRC if other failed + Added some safeties to avoid mode 1 or 2 crash for corrupted data +20000825 mvh Pass buffer size to nki_private_decompress as extra safety + Fix mode 1, added full safety against input buffer overflow + Added some comments and notes +20010507 mvh Support larger headers when coordinate information has been written +20010726 mvh Fix for decompression when information is offset in file +20011207 ljz Removed check on veclen>1000 +20020124 mvh Added test for fields by kg: non-portable types as "integer" then not swapped +20020903 ljz Made scan_header much faster +20030122 mvh Fix read of coords in compression mode 2 +20030430 mvh Fix of read coords in compression mode 2 when offset is 0 +20030717 ljz Added support for NkiCompressionModes 3 and 4 +20040426 mvh ELEKTA NKI-XVI0.1 RELEASE +20050302 mvh Estimate size of compressed data to accelerate speed of reading embedded fields +20050308 ljz+mvh ELEKTA NKI-XVI0.1j RELEASE +20071024 mvh Adapted for 64 bits +20080110 mvh ELEKTA NKI-XVI3.09 RELEASE +20080414 lsp+mgw __sun__ doesn't know +*/ + +/************************************************************************/ +/* MODULE DOCUMENTATION */ +/************************************************************************/ +/* + READ_XDR Read XDR file (may be compressed) into field + name output field handle + file_expression name of file + numerical_expression start XDR data in file offset (default 0) + NOTE: compressed XDR data may not be part of a larger file + + READ_XDR_HEADER Get entry from xdr header + %name Output = string block + file_expression file name default extension '' + %string_expression name of element to load + + READ_XDR_PREVIEW Read and downsize XDR file (for bitmap) + name output field handle + file_expression name of file + numerical_expression start XDR data in file offset (default 0) + NOTE: this command is not supported for compressed XDR files + + ENUM_XDR_HEADER + %name Output = string block + file_expression file name default extension '' + numerical_expression number of element to find name of +*/ +/************************************************************************/ +/* INCLUDE FILES */ +/************************************************************************/ + +#include +#include +#include +#include +#include +#if 0 +#ifndef __sun__ +#include +#endif +#include "mbavs2q.h" + +#ifndef QUIRT +#include +#include +#include +#else +#include "mbfield.h" +#endif +#endif + +/************************************************************************/ +/* DEFINES, ENUMERATED TYPES AND CONSTANTS */ +/************************************************************************/ +enum { + OK, + ER_ILLCOMMFUNCT, + ER_INARGUMENTS, + ER_XDR_NDIM, + ER_XDR_DIM, + ER_XDR_NSPACE, + ER_XDR_VECLEN, + ER_XDR_DATA, + ER_XDR_FIELD, + ER_XDR_OPEN, + ER_XDR_NOCTRLL, + ER_XDR_READ, + ER_OUTOFMEMORY, + ER_DECOMPRESSION, + ER_NOT_HANDLED +}; + +typedef struct +{ + unsigned int iOrgSize; + unsigned int iMode; + unsigned int iCompressedSize; + unsigned int iOrgCRC; + unsigned int iCompressedCRC; /* Excluding this header */ +} NKI_MODE2; + + +/************************************************************************/ +/* GLOBAL VARIABLES */ +/************************************************************************/ +const char* gl_ErrorMsg[] = { + "", + "Command or function not supported in this way.", + "Error in arguments", + "XDR file header NDIM error", + "XDR file header DIMn error", + "XDR file header NSPACE error", + "XDR file header VECLEN error", + "XDR file header DATA(type) error", + "XDR file header FIELD(coordinate type) error", + "XDR file could not be opened", + "XDR file header contains no ^L", + "XDR file reading error", + "Out of memory", + "Decompression failed", + "Format not handled by nkitkXDRImageIO (RECTILINEAR or IRREGULAR field)" +}; + + +static const unsigned long CRC32_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + + +/************************************************************************/ +/* PROTOTYPES */ +/************************************************************************/ +#if 0 +int Rxdr_compute(AVSfield** ppOut, char* pszFileName, int iOffset); + +int RxdrPreview_compute(AVSfield** ppOut, char* pszFileName, int iOffset); + +int RxdrHeader_compute(char *pszOut, char *pszFileName, char *pszEntry); + +int RxdrEnum_compute(char *pszOut, char *pszFileName, int iEntry); + +/******************************************************************************/ +/* AVS/QUIRT INTERFACE */ +/******************************************************************************/ + +void Rxdr_desc(void) +{ + int param; + + /* Set the module name and type */ + AVSset_module_name("XDR reader", MODULE_DATA); + + /* Create output ports for the resulting fields */ + AVScreate_output_port("Output", "field"); + + /* declare widgets */ + QUIRT_NEXT_PARAMETER_FILE(""); + param = AVSadd_parameter("FileName", "string", "/data/AVS/", NULL, ""); + AVSconnect_widget(param, "browser"); + AVSadd_parameter_prop(param, "height", "integer", 8); + + param = AVSadd_parameter("Offset", "integer", 0, 0, INT_UNBOUND); + AVSconnect_widget(param, "typein_integer"); + + AVSset_compute_proc(CF Rxdr_compute); +} +AVS_TO_QUIRT(READ_XDR, Rxdr_desc); + +void RxdrPreview_desc(void) +{ + int param; + + /* Set the module name and type */ + AVSset_module_name("XDR preview reader", MODULE_DATA); + + /* Create output ports for the resulting fields */ + AVScreate_output_port("Output", "field"); + + /* declare widgets */ + QUIRT_NEXT_PARAMETER_FILE(""); + param = AVSadd_parameter("FileName", "string", "/data/AVS/", NULL, ""); + AVSconnect_widget(param, "browser"); + AVSadd_parameter_prop(param, "height", "integer", 8); + + param = AVSadd_parameter("Offset", "integer", 0, 0, INT_UNBOUND); + AVSconnect_widget(param, "typein_integer"); + + AVSset_compute_proc(CF RxdrPreview_compute); +} +AVS_TO_QUIRT(READ_XDR_PREVIEW, RxdrPreview_desc); + +void RxdrHeader_desc(void) +{ /* Set the module name and type */ + AVSset_module_name("Read XDR header", MODULE_DATA); + + /* Create output ports for the resulting fields */ + AVSadd_parameter("Output", "string_block", "", NULL, ""); + + QUIRT_NEXT_PARAMETER_FILE(""); + AVSadd_parameter("FileName", "string", "", NULL, ""); + + AVSadd_parameter("Entry", "string", "", NULL, ""); + + AVSset_compute_proc(CF RxdrHeader_compute); +} +AVS_TO_QUIRT(READ_XDR_HEADER, RxdrHeader_desc); + +void RxdrEnum_desc(void) +{ /* Set the module name and type */ + AVSset_module_name("Enumerate XDR header", MODULE_DATA); + + /* Create output ports for the resulting fields */ + AVSadd_parameter("Output", "string_block", "", NULL, ""); + + QUIRT_NEXT_PARAMETER_FILE(""); + AVSadd_parameter("FileName", "string", "", NULL, ""); + + AVSadd_parameter("Entry", "integer", 0, INT_UNBOUND, INT_UNBOUND); + + AVSset_compute_proc(CF RxdrEnum_compute); +} +AVS_TO_QUIRT(ENUM_XDR_HEADER, RxdrEnum_desc); + +#ifndef QUIRT +AVSinit_modules(void) +{ + AVSmodule_from_desc( (int_desc_func)Rxdr_desc ); + AVSmodule_from_desc( (int_desc_func)RxdrHeader_desc ); + AVSmodule_from_desc( (int_desc_func)RxdrEnum_desc ); +} +#endif +#endif +/************************************************************************/ +/* MODULE FUNCTIONS */ +/************************************************************************/ + +/* simple XDR file reader */ + +/* help routine, scans XDR file header for keyword entry, returns NULL + if not found, else returns pointer to rest of line +*/ + +static char *scan_header(const char *file, const char *name, int offset, int removespaces) +{ + int i, j, iStringLength; + static char temp[512]; + FILE *f; + char *p, *q; + + if ((f = fopen(file, "rt")) == NULL) return NULL; + if (offset) fseek(f, offset, SEEK_SET); + + for (i=0; i<200; ) + { + if (fgets(temp, 500, f) == NULL ) break; /* end of file */ + + if (removespaces) + { + temp[500] = 0; + p = q = temp; /* remove spaces */ + iStringLength = strlen(temp); + for (j=0; j2x compression and a very good speed + + This code is not valid on HIGHENDIAN (high byte first) machines +*/ + +static int global_len; + +static int nki_private_decompress(short int *dest, signed char *src, int size) +{ + int npixels, retvalue, mode, iMode, val, j; + NKI_MODE2* pHeader = (NKI_MODE2*)src; + unsigned long iCRC=0, iCRC2=0; + //unsigned char* pDestStart = (unsigned char*)dest; + signed char *save, *end; + + retvalue = npixels = pHeader->iOrgSize; + iMode = pHeader->iMode; // safety: this value is checked in case statement + + if (npixels<1) return 0; // safety: check for invalid npixels value + + /* Up till now only Mode=1, 2, 3, and 4 are supported */ + + switch (iMode) + { + case 1: + save = src; + + src += 8; // mode 1 only has 8 bytes header: iOrgSize and iMode + end = src + size - 3; // for overflow check if we are close to end of input buffer + + *dest = *(short int *)src; + src += 2; + npixels--; + + do + { + if (src > end) // check whether the last few messages fit in input buffer + { + if (src= -64 && val <= 63) mode = 1; // 7 bit difference + else if (val==0x7f) mode = 3; // 16 bit value + else if ((val&0xff)==0x80) mode = 2; // run length encoding + else mode = 2; + + if (src+mode > end+3) + return 0; // safety: overflow input data + } + + val = *src; + + if (val >= -64 && val <= 63) // 7 bit difference + { + dest[1] = dest[0] + val; + dest++; + src++; + } + else if (val==0x7f) // 16 bit value + { + dest[1] = val = ((int)(((unsigned char *)src)[1])<<8) + ((unsigned char*)src)[2]; + dest++; + src+=3; + } + else if ((val&0xff)==0x80) // run length encoding + { + mode = ((unsigned char *)src)[1]; + npixels -= mode-1; + if (npixels<=0) return 0; // safety: overflow output data + do + { + dest[1] = dest[0]; + dest++; + } + while (--mode); + src+=2; + } + else + { + signed short diff = ((val^0x40)<<8) + (unsigned char)(src[1]); + dest[1] = dest[0] + diff; // 15 bit difference + dest++; + src+=2; + } + } + while (--npixels); + + global_len = src-save; + + break; + + case 2: + src += sizeof(NKI_MODE2); + save = src; + end = src + pHeader->iCompressedSize - 3; + + if (end > src + size - 3) + end = src + size - 3; // may occur if pHeader is corrupted + + *dest = val = *(short int *)src; + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); + src+=2; + + npixels--; + + do + { + if (src > end) // check whether the last few messages fit in input buffer + { + if (src= -64 && val <= 63) mode = 1; // 7 bit difference + else if (val==0x7f) mode = 3; // 16 bit value + else if ((val&0xff)==0x80) mode = 2; // run length encoding + else mode = 2; + + if (src+mode > end+3) + break; // safety: overflow input data + } + + val = *src; + + if (val >= -64 && val <= 63) // 7 bits difference + { + dest[1] = val = dest[0] + val; + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); + dest++; + src++; + } + else if (val==0x7f) // 16 bit value + { + dest[1] = val = ((int)(((unsigned char *)src)[1])<<8) + ((unsigned char*)src)[2]; + + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); + dest++; + src+=3; + } + else if ((val&0xff)==0x80) // run length encoding + { + mode = ((unsigned char *)src)[1]; + npixels -= mode-1; + if (npixels<=0) break; // safety: overflow output data + do + { + dest[1] = val = dest[0]; + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); + dest++; + } + while (--mode); + src+=2; + } + else + { + signed short diff = ((val^0x40)<<8) + ((unsigned char *)src)[1]; + dest[1] = val = dest[0] + diff; // 15 bit difference + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); + dest++; + src+=2; + } + } + while (--npixels); + + if (iCRC2 != pHeader->iOrgCRC) // if error in output CRC: + { + src = save; // check input CRC + while (src < end) + { + iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)src[0]] ^ ((iCRC >> 8)); + src++; + } + + if (iCRC != pHeader->iCompressedCRC) + { + AVSerror("XDR decompression: the file is corrupted"); + retvalue=0; + } + else + { + AVSerror("XDR decompression: internal error"); + retvalue=0; + } + } + + global_len = sizeof(NKI_MODE2) + pHeader->iCompressedSize; + + break; + + case 3: + save = src; + + src += 8; // mode 3 only has 8 bytes header: iOrgSize and iMode + end = src + size - 3; // for overflow check if we are close to end of input buffer + + *dest = *(short int *)src; + src += 2; + npixels--; + + do + { + if (src > end) // check whether the last few messages fit in input buffer + { + if (src= -63 && val <= 63) mode = 1; // 7 bit difference + else if (val==0x7f) mode = 3; // 16 bit value + else if ((val&0xff)==0x80) mode = 2; // run length encoding + else if ((val&0xff)==0xC0) mode = 2; // 4 bit encoding + else mode = 2; + + if (src+mode > end+3) + return 0; // safety: overflow input data + } + + val = *src; + + if (val >= -63 && val <= 63) // 7 bit difference + { + dest[1] = dest[0] + val; + dest++; + src++; + } + else if (val==0x7f) // 16 bit value + { + dest[1] = val = ((int)(((unsigned char *)src)[1])<<8) + ((unsigned char*)src)[2]; + dest++; + src+=3; + } + else if ((val&0xff)==0x80) // run length encoding + { + mode = ((unsigned char *)src)[1]; + npixels -= mode-1; + if (npixels<=0) return 0; // safety: overflow output data + do + { + dest[1] = dest[0]; + dest++; + } + while (--mode); + src+=2; + } + else if ((val&0xff)==0xC0) // 4 bit run + { + mode = ((unsigned char *)src)[1]; + npixels -= mode-1; + mode/=2; + src+=2; + if (npixels<=0) return 0; // safety: overflow output data + do + { + val = *src++; + dest[1] = dest[0] + (val>>4); + dest++; + if (val&8) val |= 0xfffffff0; + else val &= 0x0f; + dest[1] = dest[0] + val; + dest++; + } + while (--mode); + } + else + { + signed short diff = ((val^0x40)<<8) + (unsigned char)(src[1]); + dest[1] = dest[0] + diff; // 15 bit difference + dest++; + src+=2; + } + } + while (--npixels); + + global_len = src-save; + + break; + + case 4: + src += sizeof(NKI_MODE2); + save = src; + end = src + pHeader->iCompressedSize - 3; + + if (end > src + size - 3) + end = src + size - 3; // may occur if pHeader is corrupted + + *dest = val = *(short int *)src; + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); + src += 2; + npixels--; + + do + { + if (src > end) // check whether the last few messages fit in input buffer + { + if (src= -63 && val <= 63) mode = 1; // 7 bit difference + else if (val==0x7f) mode = 3; // 16 bit value + else if ((val&0xff)==0x80) mode = 2; // run length encoding + else if ((val&0xff)==0xC0) mode = 2; // 4 bit encoding + else mode = 2; + + if (src+mode > end+3) + return 0; // safety: overflow input data + } + + val = *src; + + if (val >= -63 && val <= 63) // 7 bit difference + { + dest[1] = val = dest[0] + val; + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); + dest++; + src++; + } + else if (val==0x7f) // 16 bit value + { + dest[1] = val = ((int)(((unsigned char *)src)[1])<<8) + ((unsigned char*)src)[2]; + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); + dest++; + src+=3; + } + else if ((val&0xff)==0x80) // run length encoding + { + mode = ((unsigned char *)src)[1]; + npixels -= mode-1; + if (npixels<=0) return 0; // safety: overflow output data + do + { + dest[1] = val = dest[0]; + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); + dest++; + } + while (--mode); + src+=2; + } + else if ((val&0xff)==0xC0) // 4 bit run + { + mode = ((unsigned char *)src)[1]; + npixels -= mode-1; + mode/=2; + src+=2; + if (npixels<=0) return 0; // safety: overflow output data + do + { + val = *src++; + dest[1] = j = dest[0] + (val>>4); + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)j] ^ ((iCRC2 >> 8)); + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(j>>8)] ^ ((iCRC2 >> 8)); + dest++; + if (val&8) val |= 0xfffffff0; + else val &= 0x0f; + dest[1] = j = dest[0] + val; + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)j] ^ ((iCRC2 >> 8)); + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(j>>8)] ^ ((iCRC2 >> 8)); + dest++; + } + while (--mode); + } + else + { + signed short diff = ((val^0x40)<<8) + (unsigned char)(src[1]); + dest[1] = val = dest[0] + diff; // 15 bit difference + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); + iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); + dest++; + src+=2; + } + } + while (--npixels); + + if (iCRC2 != pHeader->iOrgCRC) // if error in output CRC: + retvalue=0; + + global_len = sizeof(NKI_MODE2) + pHeader->iCompressedSize; + + break; + + + default: + AVSerror("XDR decompression: unsupported mode"); + return 0; + } + + return retvalue; +} + + +//==================================================================== +// Read image information (copied from XDRreader) +int nkitk::XDRImageIO::ReadImageInformationWithError() +{ + int offset=0; + itk::Vector dim; + int veclen=1; //, data=AVS_TYPE_BYTE, field=UNIFORM; +#if 0 + int iNkiCompression = 0; +#endif + int total=1/*, datasize=0, iNumRead, HeaderSize*/; + unsigned int coords=0,i,j,ndim,nspace; + char temp[512]; + FILE *fstream; + char *c; +#if 0 + char *buff; + AVSfield FieldTemplate; +#endif + long swap_test = 0x1000000; /* first byte is 1 when low-endian */ + forcenoswap=0; + char *file = const_cast(m_FileName.c_str()); + AVSType field=UNIFORM; + + + fstream = fopen(file, "rt"); + if (fstream == NULL) return ER_XDR_OPEN; + + fgets(temp, 500, fstream); + fclose(fstream); + + if (memcmp(temp, "# AVS field file (produced by avs_nfwrite.c)", 44)==0) forcenoswap=1; + + c = scan_header(file, "ndim", offset, 1); + if (!c) return ER_XDR_NDIM; + + ndim = atoi(c); + if (ndim<1 || ndim>MAXDIM) return ER_XDR_NDIM; + SetNumberOfDimensions(ndim); + + nspace = ndim; + + for (i=0; i MAXDIM) return ER_XDR_NSPACE; + if (nspace != ndim) return ER_NOT_HANDLED; + + c = scan_header(file, "veclen", offset, 1); + if (c) veclen = atoi(c); + if (veclen<0 /*|| veclen>1000*/) return ER_XDR_VECLEN; + SetNumberOfComponents(veclen); + if (veclen==1) SetPixelType(itk::ImageIOBase::SCALAR); + else SetPixelType(itk::ImageIOBase::VECTOR); + + c = scan_header(file, "data", offset, 1); + if (c) + { + if (memicmp(c, "byte", 4) == 0 || memicmp(c, "xdr_byte", 8) == 0) SetComponentType(itk::ImageIOBase::CHAR); + else if (memicmp(c, "short", 5) == 0 || memicmp(c, "xdr_short", 9) == 0) SetComponentType(itk::ImageIOBase::SHORT); + else if (memicmp(c, "int" , 3) == 0 || memicmp(c, "xdr_int" , 7) == 0) SetComponentType(itk::ImageIOBase::INT); + else if (memicmp(c, "real", 4) == 0 || memicmp(c, "xdr_real", 8) == 0) SetComponentType(itk::ImageIOBase::FLOAT); + else if (memicmp(c, "float", 5) == 0 || memicmp(c, "xdr_float", 9) == 0) SetComponentType(itk::ImageIOBase::FLOAT); + else if (memicmp(c, "double",6) == 0 || memicmp(c, "xdr_double",10)== 0) SetComponentType(itk::ImageIOBase::DOUBLE); + else return ER_XDR_DATA; + + if (memicmp(c, "xdr_", 4) == 0) forcenoswap=0; + } + + //Read coords here + c = scan_header(file, "field", offset, 1); + if (c) + { + if (memicmp(c, "unifo", 5) == 0) field=UNIFORM, coords=nspace *2; + else if (memicmp(c, "recti", 5) == 0) field=RECTILINEAR; + else if (memicmp(c, "irreg", 5) == 0) field=IRREGULAR, coords=total*nspace; + else return ER_XDR_FIELD; + } + else + coords=0; + + if (coords) /* expect AVS coordinates ? */ + { + coords *= sizeof(float); + fstream = fopen(m_FileName.c_str(), "rb"); + if (fstream == NULL) return ER_XDR_OPEN; + + float *points = (float *)malloc(coords); + if (points == NULL) return ER_OUTOFMEMORY; + + //Seek to coordinates position in file + if (fseek(fstream,-static_cast(coords),SEEK_END)) return ER_XDR_READ; + if (fread( /*(*output)->*/points, 1, coords, fstream ) == coords) + { /* swap data if read-ok and required (xdr is low-endian) */ + if (!(*(char *)(&swap_test)) && !forcenoswap) + { + c = (char *)/*(*output)->*/points; + for (i=0; i0.1) { + free(points); + fclose(fstream); + return ER_NOT_HANDLED; + } + } + points += (int)GetDimensions(i); + } + for (i=0; i(m_FileName.c_str()); + int offset=0; + AVSType field=UNIFORM; + + for (i=0; i(i)+2-static_cast(iNumRead), SEEK_CUR); + + if (total && iNkiCompression) + { + long iCurPos; + unsigned long iSize; + signed char* pCompressed; + + /* Read or guess the size of the compressed data */ + iCurPos = ftell(fstream); + iSize = get_nki_compressed_size(fstream); + + if (iSize==0) + { + fseek(fstream, 0, SEEK_END); + iSize = ftell(fstream); + iSize = iSize - iCurPos - coords; + + // Get compressed size from header if possible; else use uncompressed size as safe estimate + if (iSize>total && offset) iSize=total+8; + } + + fseek(fstream, iCurPos, SEEK_SET); + + /* Allocate space for the compressed pixels */ + pCompressed = (signed char*)malloc(iSize); + if (!pCompressed) + { + fclose(fstream); +#if 0 + if (*output) AVSfield_free(*output); + *output = NULL; +#endif + return ER_OUTOFMEMORY; + } + + /* Read the compressed pixels */ + if (fread( (void *)pCompressed, 1, iSize, fstream ) != iSize) + { + fclose(fstream); +#if 0 + if (*output) AVSfield_free(*output); + *output = NULL; +#endif + return ER_XDR_READ; + } + + if (!nki_private_decompress((short*)buffer, pCompressed, iSize)) + { + fclose(fstream); +#if 0 + if (*output) AVSfield_free(*output); + *output = NULL; +#endif + return ER_DECOMPRESSION; + } + + // if (offset) + fseek(fstream, iCurPos + global_len, SEEK_SET); + + free(pCompressed); + goto READ_COORDS; + } + + + if (total) + { + if (fread( (void *)buffer, 1, total, fstream ) != total) + { + fclose(fstream); +#if 0 + if (*output) AVSfield_free(*output); + *output = NULL; +#endif + return ER_XDR_READ; + } + } + + /* swap data if required (xdr is low-endian) */ + + datasize = GetComponentSize(); + if (!(*(char *)(&swap_test)) && !forcenoswap) + { + if (datasize==2) + { + c = (char *)buffer; + for (i=0; ipoints, 1, coords, fstream ) == coords) + { /* swap data if read-ok and required (xdr is low-endian) */ + + if (!(*(char *)(&swap_test)) && !forcenoswap) + { + c = (char *)(*output)->points; + for (i=0; iMAXDIM) return ER_XDR_NDIM; + nspace = ndim; + + /* defaults for dimensions and downsize */ + + for (i=0; i200000L) return ER_XDR_DIM; + + total *= dim[i]; + coords += dim[i]; + } + + c = scan_header(file, "nspace", offset, 1); + if (c) nspace = atoi(c); + if (nspace<1 || ndim > MAXDIM) return ER_XDR_NSPACE; + + c = scan_header(file, "veclen", offset, 1); + if (c) veclen = atoi(c); + if (veclen<0 || veclen>100) return ER_XDR_VECLEN; + + c = scan_header(file, "data", offset, 1); + + if (c) + { + if (memicmp(c, "byte", 4) == 0) data=AVS_TYPE_BYTE, datasize=1; + else if (memicmp(c, "short", 5) == 0) data=AVS_TYPE_SHORT, datasize=2; + else if (memicmp(c, "int" , 3) == 0) data=AVS_TYPE_INTEGER,datasize=4; + else if (memicmp(c, "real", 4) == 0) data=AVS_TYPE_REAL, datasize=4; + else if (memicmp(c, "float", 5) == 0) data=AVS_TYPE_REAL, datasize=4; + else if (memicmp(c, "double",6) == 0) data=AVS_TYPE_DOUBLE, datasize=8; + + else if (memicmp(c, "xdr_byte", 8) == 0) data=AVS_TYPE_BYTE, datasize=1, forcenoswap=0; + else if (memicmp(c, "xdr_short", 9) == 0) data=AVS_TYPE_SHORT, datasize=2, forcenoswap=0; + else if (memicmp(c, "xdr_int" , 7) == 0) data=AVS_TYPE_INTEGER,datasize=4, forcenoswap=0; + else if (memicmp(c, "xdr_real", 8) == 0) data=AVS_TYPE_REAL, datasize=4, forcenoswap=0; + else if (memicmp(c, "xdr_float", 9) == 0) data=AVS_TYPE_REAL, datasize=4, forcenoswap=0; + else if (memicmp(c, "xdr_double",10)== 0) data=AVS_TYPE_DOUBLE, datasize=8, forcenoswap=0; + else return ER_XDR_DATA; + } + + c = scan_header(file, "field", offset, 1); + if (c) + { + if (memicmp(c, "unifo", 5) == 0) field=UNIFORM, coords=nspace*2; + else if (memicmp(c, "recti", 5) == 0) field=RECTILINEAR; + else if (memicmp(c, "irreg", 5) == 0) field=IRREGULAR, coords=total*nspace; + else return ER_XDR_FIELD; + } + else + coords=0; + + c = scan_header(file, "nki_compression", offset, 1); + if (c) iNkiCompression = atoi(c); + if (iNkiCompression) + { + fclose(fstream); + return ER_ILLCOMMFUNCT; + } + + FIELDdefault(&FieldTemplate); + FieldTemplate.ndim = ndim; + FieldTemplate.nspace = nspace; + FieldTemplate.veclen = veclen; + FieldTemplate.type = data; + FieldTemplate.uniform = field; + FieldTemplate.size = datasize; + + fstream = fopen(file, "rb"); + + if (fstream == NULL) + return ER_XDR_OPEN; + + buff = (char *)malloc(8192); + if (buff == NULL) + { + return ER_OUTOFMEMORY; + } + memset(buff, 0, 8192); + fseek(fstream, offset, SEEK_SET); + + while (1) + { + if (fgets(temp, 500, fstream) == NULL ) + return ER_XDR_NOCTRLL; /* end of file */ + + if (temp[0] == 10) continue; + + if (temp[0] == 12) + { + fseek(fstream, -2, SEEK_CUR); + break; + } /* ^L end of header */ + + if (temp[0] != '#') break; + } + start = ftell(fstream); + + iNumRead = fread(buff, 1, 8192, fstream); + if (iNumRead < 1) + { + free(buff); + fclose(fstream); + return ER_XDR_READ; + } + + for (i=0; i=3) + { + if (dim[0]==dim[1]) sliceax = 2; + else sliceax = 1; + } + + total = 1; + + for (i=0; ifield_data); + + buff = (char *)malloc(dim[0] * datasize * veclen); + + for (i=0; ifield_data; + for (i=0; ifield_data; + for (i=0; ifield_data; + for (i=0; ipoints, coords ) == coords) + { if (!(*(char *)(&swap_test)) && !forcenoswap) + { c = (char *)(*output)->points; + for (i=0; i + + vvCropDialog + + + + 0 + 0 + 285 + 276 + + + + Crop Image + + + + :/new/prefix1/icons/crop.png:/new/prefix1/icons/crop.png + + + + + + + + Input Image + + + + + + + + + + + + + + X min + + + + + + + Qt::Horizontal + + + + + + + X max + + + + + + + Qt::Horizontal + + + + + + + Y min + + + + + + + Qt::Horizontal + + + + + + + Y max + + + + + + + Qt::Horizontal + + + + + + + Z min + + + + + + + Qt::Horizontal + + + + + + + Z max + + + + + + + Qt::Horizontal + + + + + + + + + + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + vvCropDialog + accept() + + + 184 + 271 + + + 157 + 262 + + + + + buttonBox + rejected() + vvCropDialog + reject() + + + 184 + 271 + + + 286 + 262 + + + + + xminSlider + valueChanged(int) + spin_xmin + setValue(int) + + + 171 + 77 + + + 246 + 80 + + + + + spin_xmin + valueChanged(int) + xminSlider + setValue(int) + + + 251 + 71 + + + 169 + 70 + + + + + xmaxSlider + valueChanged(int) + spin_xmax + setValue(int) + + + 172 + 109 + + + 233 + 111 + + + + + spin_xmax + valueChanged(int) + xmaxSlider + setValue(int) + + + 241 + 110 + + + 167 + 111 + + + + + yminSlider + valueChanged(int) + spin_ymin + setValue(int) + + + 170 + 131 + + + 245 + 138 + + + + + spin_ymin + valueChanged(int) + yminSlider + setValue(int) + + + 259 + 136 + + + 179 + 135 + + + + + ymaxSlider + valueChanged(int) + spin_ymax + setValue(int) + + + 177 + 168 + + + 257 + 172 + + + + + spin_ymax + valueChanged(int) + ymaxSlider + setValue(int) + + + 261 + 168 + + + 172 + 163 + + + + + zminSlider + valueChanged(int) + spin_zmin + setValue(int) + + + 184 + 199 + + + 269 + 198 + + + + + spin_zmin + valueChanged(int) + zminSlider + setValue(int) + + + 264 + 197 + + + 197 + 197 + + + + + zmaxSlider + valueChanged(int) + spin_zmax + setValue(int) + + + 139 + 229 + + + 266 + 227 + + + + + spin_zmax + valueChanged(int) + zmaxSlider + setValue(int) + + + 249 + 222 + + + 163 + 221 + + + + + diff --git a/vv/qt_ui/vvDeformationDialog.ui b/vv/qt_ui/vvDeformationDialog.ui new file mode 100644 index 0000000..3f6fcf6 --- /dev/null +++ b/vv/qt_ui/vvDeformationDialog.ui @@ -0,0 +1,215 @@ + + vvDeformationDialog + + + + 0 + 0 + 405 + 309 + + + + Deformation field computation + + + + + + Input Sequence + + + + + + + + + + Reference Image (0) + + + + + + + Qt::Horizontal + + + QSlider::TicksAbove + + + 1 + + + + + + + Maximum number of iterations + + + + + + + 1 + + + 1000000 + + + 10 + + + 3000 + + + + + + + Number of consecutive useless iterations before stop + + + true + + + + + + + 100000 + + + 500 + + + + + + + Alpha + + + + + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + Sigma + + + + + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + Number of threads + + + + + + + 1 + + + 99 + + + 1 + + + + + + + Ouput file name + + + + + + + + + output_vf.mhd + + + + + + + Chose file + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + + + + + + + + buttonBox + rejected() + vvDeformationDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + buttonBox + accepted() + vvDeformationDialog + accept() + + + 239 + 266 + + + 219 + 223 + + + + + diff --git a/vv/qt_ui/vvDicomSeriesSelector.ui b/vv/qt_ui/vvDicomSeriesSelector.ui new file mode 100644 index 0000000..3d60209 --- /dev/null +++ b/vv/qt_ui/vvDicomSeriesSelector.ui @@ -0,0 +1,366 @@ + + vvDicomSeriesSelector + + + Qt::WindowModal + + + + 0 + 0 + 943 + 645 + + + + true + + + Qt::WheelFocus + + + Dicom Series Selector + + + + 6 + + + 9 + + + + + Qt::Vertical + + + + QFrame::Panel + + + QFrame::Raised + + + 1 + + + + 9 + + + 6 + + + + + Qt::Horizontal + + + + + + + + + Search in this folder : + + + + + + + false + + + true + + + + + + + ... + + + + + + + + + + + Search recursively + + + + + + + Search DICOM + + + + + + + + + true + + + Qt::TabFocus + + + QAbstractItemView::AnyKeyPressed|QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed + + + true + + + true + + + QAbstractItemView::SelectRows + + + QListView::ListMode + + + 0 + + + -1 + + + + + + + + + + + 6 + + + 0 + + + + + + 0 + 0 + + + + <b>Current DICOM serie</b> + + + Qt::RichText + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + + + + Qt::RichText + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 9 + + + 6 + + + + + Qt::Horizontal + + + + + 6 + + + 0 + + + + + + 0 + 0 + + + + <b>Files in current DICOM serie</b> + + + Qt::RichText + + + + + + + Qt::TabFocus + + + true + + + + + + + + + 6 + + + 0 + + + + + + 0 + 0 + + + + <b>Current DICOM file</b> + + + Qt::RichText + + + + + + + + + + + + + + + + + + 6 + + + 0 + + + + + <font color="blue">(1)</font> Select a folder, <font color="blue">(2)</font> Press <b>Search DICOM</b>, <br> <font color="blue">(3)</font> Select a serie ID in the left table, <font color="blue">(4)</font> Press <b>Open</b> + + + Qt::RichText + + + + + + + Qt::Horizontal + + + + 141 + 20 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Open + + + + + + + + + mDicomDetailsListWidget + mButtonBox + mDicomDetailsLabel + + + + + mButtonBox + accepted() + vvDicomSeriesSelector + accept() + + + 248 + 254 + + + 157 + 274 + + + + + mButtonBox + rejected() + vvDicomSeriesSelector + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/vv/qt_ui/vvDocumentation.ui b/vv/qt_ui/vvDocumentation.ui new file mode 100644 index 0000000..8bb0792 --- /dev/null +++ b/vv/qt_ui/vvDocumentation.ui @@ -0,0 +1,110 @@ + + + vvDocumentation + + + + 0 + 0 + 714 + 565 + + + + About + + + + + + + + + 2 + + + 2 + + + + + + + + :/new/prefix1/icons/splashscreen2.png + + + true + + + Qt::AlignCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Ok + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Press 'Ctrl+h' to obtain navigation help ! + + + Qt::AlignCenter + + + + + + + + + + + okButton + clicked() + vvDocumentation + accept() + + + 218 + 493 + + + 311 + 488 + + + + + diff --git a/vv/qt_ui/vvDummyWindow.ui b/vv/qt_ui/vvDummyWindow.ui new file mode 100644 index 0000000..d443bc9 --- /dev/null +++ b/vv/qt_ui/vvDummyWindow.ui @@ -0,0 +1,65 @@ + + + vvDummyWindow + + + + 0 + 0 + 589 + 475 + + + + DummyApp™ + + + + + + 150 + 130 + 291 + 181 + + + + OK + + + + + + + 0 + 0 + 589 + 22 + + + + + + + + + pushButton + clicked() + vvDummyWindow + Run() + + + 244 + 205 + + + 74 + 174 + + + + + + Run() + + diff --git a/vv/qt_ui/vvHelpDialog.ui b/vv/qt_ui/vvHelpDialog.ui new file mode 100644 index 0000000..b1cce67 --- /dev/null +++ b/vv/qt_ui/vvHelpDialog.ui @@ -0,0 +1,166 @@ + + + vvHelpDialog + + + + 0 + 0 + 763 + 471 + + + + Navigation Help + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; font-weight:600; text-decoration: underline;">Slice Selection</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt; font-weight:600;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; font-weight:600;">F1:</span><span style=" font-size:12pt;"> Sagital</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; font-weight:600;">F2: </span><span style=" font-size:12pt;">Coronal</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; font-weight:600;">F3: </span><span style=" font-size:12pt;">Axial</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; font-weight:600;">F5: </span><span style=" font-size:12pt;">Horizontal Flip</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; font-weight:600;">F6</span><span style=" font-size:12pt;">: Vertical Flip</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; font-weight:600; text-decoration: underline;">Windowing</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; font-weight:600;">0,1,2,3,4,5</span><span style=" font-size:12pt;"> : Windowing Preset Selection</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; font-weight:600;">6,7,8,9</span><span style=" font-size:12pt;">: Colormap Selection</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; font-weight:600;">i</span><span style=" font-size:12pt;">: Toggle interpolation</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; font-weight:600;">u</span><span style=" font-size:12pt;">: Toggle contour superposition mode</span></p></body></html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; font-weight:600; text-decoration: underline;">Navigation</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><span style=" font-weight:600;">r</span>: Reset View</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><span style=" font-weight:600;">l</span>: Reload Image</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><span style=" font-weight:600;">f</span>: Fly To Mouse Position</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><span style=" font-weight:600;">g</span>: Go to Crosshair Position</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><span style=" font-weight:600;">h</span>: Hide Crosshair</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><span style=" font-weight:600;">Up,Down</span>: Change Slice</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><span style=" font-weight:600;">Left, Right</span>: Change Temporal Slice</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><span style=" font-weight:600; text-decoration: underline;">Mouse</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><span style=" font-weight:600;">w,x or Ctrl+Wheel</span>: Zoom In/Out</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><span style=" font-weight:600;">Left Button</span>: Synchronize All Views</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><span style=" font-weight:600;">Middle Button</span>: Grab Image</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><span style=" font-weight:600;">Right Button</span>: Change Windowing</p></body></html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 0 + 20 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + OK + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + pushButton + clicked() + vvHelpDialog + accept() + + + 130 + 659 + + + 210 + 645 + + + + + diff --git a/vv/qt_ui/vvInfoPanel.ui b/vv/qt_ui/vvInfoPanel.ui new file mode 100644 index 0000000..9768d2f --- /dev/null +++ b/vv/qt_ui/vvInfoPanel.ui @@ -0,0 +1,497 @@ + + + vvInfoPanel + + + + 0 + 0 + 295 + 439 + + + + + 0 + 0 + + + + Form + + + + + + true + + + + + 0 + 0 + 273 + 417 + + + + + + + + 0 + 0 + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; color:#0000ff;">Image :</span></p></body></html> + + + + + + + + + + + + + + + 0 + 0 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:9pt;"><span style=" font-weight:600;"> Dimension :</span></p></body></html> + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:9pt;"><span style=" font-weight:600;"> Size (pixel) :</span></p></body></html> + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:9pt;"><span style=" font-weight:600;"> Size in mm :</span></p></body></html> + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:9pt;"><span style=" font-weight:600;"> Origin :</span></p></body></html> + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:9pt;"><span style=" font-weight:600;"> Spacing :</span></p></body></html> + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;"> # pixels :</span></p></body></html> + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; color:#0000ff;">Cross hair :</span></p></body></html> + + + + + + + + + + + + + + + 0 + 0 + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;"> Position (pixel):</span></p></body></html> + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;"> Position (mm):</span></p></body></html> + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;"> Pixel value :</span></p></body></html> + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; color:#0000ff;">Panel :</span></p></body></html> + + + + + + + + + + + + + + + 0 + 0 + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;"> Top Left :</span></p></body></html> + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> <span style=" font-weight:600;">Top Right :</span></p></body></html> + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;"> Bottom Left : </span></p></body></html> + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;"> Bottom Right :</span></p></body></html> + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + + diff --git a/vv/qt_ui/vvLandmarksPanel.ui b/vv/qt_ui/vvLandmarksPanel.ui new file mode 100644 index 0000000..d0bec19 --- /dev/null +++ b/vv/qt_ui/vvLandmarksPanel.ui @@ -0,0 +1,143 @@ + + + vvLandmarksPanel + + + + 0 + 0 + 325 + 131 + + + + Form + + + + 2 + + + 2 + + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">CurrentImage :</span></p></body></html> + + + + + + + 7 + + + + # + + + + + x + + + + + y + + + + + z + + + + + t + + + + + pixel value + + + + + Comments + + + + + + + + + 0 + 0 + + + + remove last landmark. + + + + + + + :/new/prefix1/icons/undo.png:/new/prefix1/icons/undo.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Load + + + + :/new/prefix1/icons/open.png:/new/prefix1/icons/open.png + + + + + + + Save + + + + :/new/prefix1/icons/filesave.png:/new/prefix1/icons/filesave.png + + + + + + + Coordinates are in mm + + + + + + + + + + diff --git a/vv/qt_ui/vvLinkPanel.ui b/vv/qt_ui/vvLinkPanel.ui new file mode 100644 index 0000000..237a9b7 --- /dev/null +++ b/vv/qt_ui/vvLinkPanel.ui @@ -0,0 +1,116 @@ + + + vvLinkPanel + + + + 0 + 0 + 276 + 254 + + + + Form + + + + + + false + + + + + + + + New Column + + + + + New Column + + + + + + + + Choose images to link : + + + + + + + + + + + + + 0 + 0 + + + + & + + + + + + + + + + + 0 + 0 + + + + Link + + + + + + + + + Link all currently opened images + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Link all + + + + + + + + + + diff --git a/vv/qt_ui/vvMainWindow.ui b/vv/qt_ui/vvMainWindow.ui new file mode 100644 index 0000000..b35f032 --- /dev/null +++ b/vv/qt_ui/vvMainWindow.ui @@ -0,0 +1,1119 @@ + + + vvMainWindow + + + + 0 + 0 + 1008 + 758 + + + + + 0 + 0 + + + + vv : the 4D Slicer + + + + :/new/prefix1/icons/ducky.png:/new/prefix1/icons/ducky.png + + + Type 'h' on image to display help on navigation + + + + + 0 + 0 + + + + Type 'h' on image to display help on navigation + + + + + + + 0 + 0 + + + + + 16 + 36 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 2 + + + 2 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 24 + 24 + + + + Go to cursor + + + + + + + :/new/prefix1/icons/cross.png:/new/prefix1/icons/cross.png + + + + + + + QFrame::Sunken + + + Qt::Vertical + + + + + + + + 0 + 0 + + + + + 24 + 24 + + + + Play Current Image + + + + + + + :/new/prefix1/icons/player_play.png:/new/prefix1/icons/player_play.png + + + + + + + Qt::Vertical + + + + + + + Window : + + + + + + + 3 + + + -66000.000000000000000 + + + 66000.000000000000000 + + + 10.000000000000000 + + + + + + + + 0 + 0 + + + + + 24 + 16777215 + + + + Inverse colors + + + + + + + :/new/prefix1/icons/invertcolor.png:/new/prefix1/icons/invertcolor.png + + + + + + + Level : + + + + + + + 3 + + + -66000.000000000000000 + + + 66000.000000000000000 + + + 10.000000000000000 + + + + + + + Preset : + + + + + + + + 0 + 0 + + + + + 100 + 16777215 + + + + + Auto Scale + + + + + Hounsfield Full Scale + + + + + Soft Tissue + + + + + Lungs + + + + + Bones + + + + + [0,1] Scale + + + + + User Scale + + + + + Ventilation Image + + + + + + + + Colormap : + + + + + + + + B&W + + + + + Heat + + + + + Cold + + + + + Full Color + + + + + Segmentation + + + + + Ventilation + + + + + + + + + 0 + 0 + + + + + 24 + 24 + + + + Expand window + + + + + + + :/new/prefix1/icons/adjustsize.png:/new/prefix1/icons/adjustsize.png + + + + + + + Qt::Vertical + + + + + + + 1 + + + 50 + + + 10 + + + + + + + Speed : + + + + + + + + + + Qt::Horizontal + + + + Qt::Vertical + + + + + 0 + 1 + + + + 0 + + + + Images + + + + 2 + + + 2 + + + + + + 0 + 0 + + + + Qt::ScrollBarAsNeeded + + + false + + + Qt::ElideLeft + + + true + + + 7 + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + Data + + + + + 6 + + + + + 8 + + + + + + + + + + 0 + 0 + + + + Overlay + + + + 2 + + + 2 + + + + + + 0 + 0 + + + + + + + + + + 0 + 0 + + + + Link + + + + 2 + + + 2 + + + + + + 0 + 0 + + + + + + + + + + 0 + 0 + + + + Landmarks + + + + 2 + + + 2 + + + + + + 0 + 0 + + + + + + + + + + true + + + + 0 + 0 + + + + + + + + 1 + 0 + + + + Qt::Horizontal + + + + Qt::Vertical + + + + + 0 + 0 + + + + + 2 + + + 2 + + + + + ArrowCursor + + + true + + + Qt::WheelFocus + + + + + + + Qt::Vertical + + + + + + + Qt::Horizontal + + + + + + + + + 0 + 0 + + + + Qt::NoFocus + + + + 2 + + + 2 + + + + + true + + + Qt::NoFocus + + + + + + + Qt::Vertical + + + + + + + Qt::Horizontal + + + + + + + + + Qt::Vertical + + + + + 0 + 0 + + + + + 2 + + + 2 + + + + + true + + + + + + + Qt::Vertical + + + + + + + Qt::Horizontal + + + + + + + + + 0 + 0 + + + + + 2 + + + 2 + + + + + + 0 + 0 + + + + true + + + + + + + Qt::Vertical + + + + + + + Qt::Horizontal + + + + + + + + + + + + + + + 0 + 0 + 1008 + 22 + + + + false + + + + File + + + + + + + + + + + + + + + + + + Help + + + + + + + Overlay + + + + + + + Screenshots + + + + + + + + + Tools + + + + + + + + + + + + + + + + + + + + :/new/prefix1/icons/fileopen.png:/new/prefix1/icons/fileopen.png + + + Open image(s) + + + + + Close images + + + + + + :/new/prefix1/icons/exit.png:/new/prefix1/icons/exit.png + + + Exit + + + + + Save screenshot + + + + + pickable + + + + + dragable + + + + + Set colormap + + + + + IsoContours + + + + + About QtVTKRender2D + + + + + About + + + + + Reload images + + + + + + :/new/prefix1/icons/open.png:/new/prefix1/icons/open.png + + + Open Dicom + + + + + + :/new/prefix1/icons/open.png:/new/prefix1/icons/open.png + + + Open several xD images into a single (x+1) D + + + + + Open One Image As Multiple + + + + + + :/new/prefix1/icons/filesave.png:/new/prefix1/icons/filesave.png + + + Save current image + + + Ctrl+S + + + + + + :/new/prefix1/icons/cursor-uparrow.png:/new/prefix1/icons/cursor-uparrow.png + + + Add deformation field to current image + + + + + + :/new/prefix1/icons/NOgrid.png:/new/prefix1/icons/NOgrid.png + + + Save image in TL + + + + + + :/new/prefix1/icons/NEgrid.png:/new/prefix1/icons/NEgrid.png + + + Save image in TR + + + + + + :/new/prefix1/icons/SOgrid.png:/new/prefix1/icons/SOgrid.png + + + Save image in BL + + + + + + :/new/prefix1/icons/SEgrid.png:/new/prefix1/icons/SEgrid.png + + + Save image in BR + + + + + + :/new/prefix1/icons/open.png:/new/prefix1/icons/open.png + + + Open xD image(s) as (x-1)D + t + + + + + + :/new/prefix1/icons/open.png:/new/prefix1/icons/open.png + + + Open several xD images into a single xD + t + + + + + + :/new/prefix1/icons/fusion.png:/new/prefix1/icons/fusion.png + + + Add fusion image to current image + + + + + Segmentation + + + + + Resample + + + + + Surface Viewer + + + + + joelDebug + + + + + Deformable Registration + + + + + Warp image with vector field + + + + + Maximum Intensity Projection + + + + + + :/new/prefix1/icons/open.png:/new/prefix1/icons/open.png + + + Open VTK contour + + + + + Navigation Help + + + Ctrl+H + + + + + + :/new/prefix1/icons/open.png:/new/prefix1/icons/open.png + + + Open Dicom-Struct + + + + + Compute mid-position image + + + + + + QVTKWidget + QWidget +
QVTKWidget.h
+
+ + vvInfoPanel + QWidget +
vvInfoPanel.h
+
+ + vvLandmarksPanel + QWidget +
vvLandmarksPanel.h
+
+ + vvLinkPanel + QWidget +
vvLinkPanel.h
+
+ + vvOverlayPanel + QWidget +
vvOverlayPanel.h
+
+
+ + presetComboBox + windowSpinBox + levelSpinBox + NOViewWidget + NOVerticalSlider + NOHorizontalSlider + SOVerticalSlider + SOHorizontalSlider + NEVerticalSlider + NEHorizontalSlider + SEVerticalSlider + SEHorizontalSlider + viewButton + + + + + +
diff --git a/vv/qt_ui/vvOverlayPanel.ui b/vv/qt_ui/vvOverlayPanel.ui new file mode 100644 index 0000000..cf9d6c4 --- /dev/null +++ b/vv/qt_ui/vvOverlayPanel.ui @@ -0,0 +1,472 @@ + + + vvOverlayPanel + + + + 0 + 0 + 323 + 447 + + + + + 0 + 0 + + + + Form + + + + + + + 0 + 0 + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Image :</span></p></body></html> + + + + + + + true + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 2 + + + 2 + + + + + + 24 + 24 + + + + + + + :/new/prefix1/icons/cursor-uparrow.png + + + true + + + + + + + + 0 + 0 + + + + Deformation field : + + + + + + + Subsampling : + + + + + + + 1 + + + 5 + + + + + + + Scale : + + + + + + + 1 + + + + + + + + 0 + 0 + + + + Displacement : + + + + + + + + 0 + 0 + + + + Length : + + + + + + + Use Logarithm LUT + + + + + + + + + + true + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 2 + + + 2 + + + + + + 24 + 24 + + + + + + + :/new/prefix1/icons/GPSup.png + + + true + + + + + + + + 0 + 0 + + + + + + + + + + + Color : + + + + + + + 180 + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + Pixel value in image 1 : + + + + + + + + 0 + 0 + + + + Pixel value in image 2 : + + + + + + + + 0 + 0 + + + + Pixel difference : + + + + + + + + + + true + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 2 + + + 2 + + + + + + 24 + 24 + + + + + + + :/new/prefix1/icons/fusion.png + + + + + + + + 0 + 0 + + + + Fusion : + + + + + + + Opacity : + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + Colormap : + + + + + + + 3 + + + + B&W + + + + + Heat + + + + + Cold + + + + + Full Color Range + + + + + + + + Window : + + + + + + + 1 + + + -999999.000000000000000 + + + 999999.000000000000000 + + + 10.000000000000000 + + + 100.000000000000000 + + + + + + + Level : + + + + + + + 1 + + + -999999.000000000000000 + + + 999999.000000000000000 + + + 10.000000000000000 + + + 1000.000000000000000 + + + + + + + + 0 + 0 + + + + Pixel value in image 2 : + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + diff --git a/vv/qt_ui/vvProgressDialog.ui b/vv/qt_ui/vvProgressDialog.ui new file mode 100644 index 0000000..9100089 --- /dev/null +++ b/vv/qt_ui/vvProgressDialog.ui @@ -0,0 +1,58 @@ + + + vvProgressDialog + + + Qt::WindowModal + + + + 0 + 0 + 267 + 59 + + + + Progress + + + + :/new/prefix1/icons/ducky.png:/new/prefix1/icons/ducky.png + + + + + + Opening image + + + Qt::AlignCenter + + + + + + + Please wait ... + + + Qt::AlignCenter + + + + + + + 24 + + + + + + + + + + + diff --git a/vv/qt_ui/vvResamplerDialog.ui b/vv/qt_ui/vvResamplerDialog.ui new file mode 100644 index 0000000..617e4ba --- /dev/null +++ b/vv/qt_ui/vvResamplerDialog.ui @@ -0,0 +1,1259 @@ + + vvResamplerDialog + + + Qt::ApplicationModal + + + + 0 + 0 + 582 + 506 + + + + Dialog + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 4 + + + 4 + + + 4 + + + 4 + + + + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Select image to resample</span></p></body></html> + + + + + + + + + + + + + + File format + + + + + + + .mhd + + + + + + + + + + + Dimension + + + + + + + TextLabel + + + + + + + + + + + Pixel Type + + + + + + + TextLabel + + + + + + + + + + + Size + + + + + + + TextLabel + + + + + + + + + + + Spacing + + + + + + + TextLabel + + + + + + + + + + + Memory size + + + + + + + TextLabel + + + + + + + + + + + Display result? + + + + + + + + + + true + + + false + + + + + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 4 + + + 4 + + + 4 + + + 4 + + + + + + 0 + 0 + + + + Size : + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 5 + + + 2 + + + + + + 0 + 0 + + + + x : + + + + + + + + 0 + 0 + + + + + 50 + 16777215 + + + + Qt::LeftToRight + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + + + + + + 0 + 0 + + + + y : + + + + + + + + 0 + 0 + + + + + 50 + 16777215 + + + + Qt::LeftToRight + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + + + + + + 0 + 0 + + + + z : + + + + + + + true + + + + 0 + 0 + + + + + 50 + 16777215 + + + + Qt::LeftToRight + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + + + + + + + + + 0 + 0 + + + + Scale size : + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 50 + 16777215 + + + + true + + + + + + + + 0 + 0 + + + + % + + + + + + + + + + Qt::Horizontal + + + + 50 + 41 + + + + + + + + Iso-size : + + + + + + + + 0 + 0 + + + + + 50 + 16777215 + + + + true + + + + + + + Qt::Horizontal + + + + 50 + 23 + + + + + + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + Spacing : + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 5 + + + 2 + + + + + + 0 + 0 + + + + x : + + + + + + + + 0 + 0 + + + + + 50 + 16777215 + + + + Qt::LeftToRight + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + + + + + + 0 + 0 + + + + y : + + + + + + + + 0 + 0 + + + + + 50 + 16777215 + + + + Qt::LeftToRight + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + + + + + + 0 + 0 + + + + z : + + + + + + + + 0 + 0 + + + + + 50 + 16777215 + + + + Qt::LeftToRight + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + + + + + + + + + 0 + 0 + + + + Scale spacing : + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 50 + 16777215 + + + + true + + + + + + + + 0 + 0 + + + + % + + + + + + + + + + Qt::Horizontal + + + + 50 + 20 + + + + + + + + + 0 + 0 + + + + Iso-spacing : + + + + + + + + 0 + 0 + + + + + 50 + 16777215 + + + + true + + + + + + + Qt::Horizontal + + + + 50 + 20 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + Apply Gaussian Filter + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + + + + 0 + 0 + + + + Gaussian width : + + + + + + + + 40 + 16777215 + + + + + + + + + 40 + 16777215 + + + + + + + false + + + + + + + + 40 + 16777215 + + + + + + + + + + + + + Qt::Horizontal + + + + + + + + + + 0 + 0 + + + + Default pixel value : + + + + + + + + 50 + 16777215 + + + + 0.0 + + + + + + + Qt::Horizontal + + + + 121 + 21 + + + + + + + + + + Qt::Horizontal + + + + + + + + + + 0 + 0 + + + + Interpolation : + + + + + + + + NN + + + + + Linear + + + + + BSpline + + + + + Blut (faster BSpline) + + + + + + + + + + Qt::Horizontal + + + + + + + + + + 0 + 0 + + + + BSpline order : + + + + + + + 5 + + + 3 + + + + + + + + + + + + 0 + 0 + + + + + 0 + 16 + + + + BLUT sampling factor : + + + + + + + 30 + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 0 + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Output :</span></p></body></html> + + + + + + + + + Size + + + + + + + TextLabel + + + + + + + + + + + Spacing + + + + + + + TextLabel + + + + + + + + + + + Memory size + + + + + + + TextLabel + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; color:#0000ff;">Click OK when ready ...</span></p></body></html> + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + + + + + + + + + + + + + + + mOkButton + accepted() + vvResamplerDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + mOkButton + rejected() + vvResamplerDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/vv/qt_ui/vvSegmentationDialog.ui b/vv/qt_ui/vvSegmentationDialog.ui new file mode 100755 index 0000000..4767625 --- /dev/null +++ b/vv/qt_ui/vvSegmentationDialog.ui @@ -0,0 +1,159 @@ + + vvSegmentationDialog + + + + 0 + 0 + 561 + 453 + + + + Segmentation tool + + + + + + Qt::Vertical + + + + + + + Qt::Vertical + + + + + + + + + + + 0 + 0 + + + + Min : + + + + + + + Max : + + + + + + + + 0 + 0 + + + + Binarise + + + + + + + Erode + + + + + + + Dilate + + + + + + + Kernel Size : + + + + + + + 1 + + + 2 + + + + + + + + 0 + 0 + + + + 3D + + + + + + + Save As + + + + + + + Close + + + + + + + TextLabel + + + + + + + + QVTKWidget + QWidget +
QVTKWidget.h
+
+
+ + + + closeButton + clicked() + vvSegmentationDialog + reject() + + + 528 + 403 + + + 542 + 423 + + + + +
diff --git a/vv/qt_ui/vvStructSelector.ui b/vv/qt_ui/vvStructSelector.ui new file mode 100644 index 0000000..84efa43 --- /dev/null +++ b/vv/qt_ui/vvStructSelector.ui @@ -0,0 +1,81 @@ + + + vvStructSelector + + + + 0 + 0 + 365 + 389 + + + + Select contours to open + + + + + + QAbstractItemView::MultiSelection + + + + + + + false + + + Propagate contours with vector field? + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + vvStructSelector + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + vvStructSelector + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/vv/qt_ui/vvSurfaceViewerDialog.ui b/vv/qt_ui/vvSurfaceViewerDialog.ui new file mode 100644 index 0000000..6683830 --- /dev/null +++ b/vv/qt_ui/vvSurfaceViewerDialog.ui @@ -0,0 +1,74 @@ + + vvSurfaceViewerDialog + + + + 0 + 0 + 554 + 472 + + + + Dialog + + + + + + + + + Qt::Horizontal + + + + 311 + 20 + + + + + + + + Load + + + + + + + Close + + + + + + + + QVTKWidget + QWidget +
QVTKWidget.h
+
+
+ + + + closeButton + clicked() + vvSurfaceViewerDialog + reject() + + + 492 + 436 + + + 443 + 435 + + + + +
diff --git a/vv/scripts/create_mhd_4D.sh b/vv/scripts/create_mhd_4D.sh new file mode 100755 index 0000000..8eac782 --- /dev/null +++ b/vv/scripts/create_mhd_4D.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +############################################### +# create_mhd_4D argument : repertoire # +############################################### +if [ $# -lt 1 ] +then + echo "Usage: create_mhd_4D directory" + exit 1 +fi + +cd $1 +nbph=`ls -l *0.mhd | wc -l` +orig=`ls -1 *0.mhd | head -n 1` + +cat $orig | sed "s/NDims = .*/NDims = 4/ + s/TransformMatrix = .*/TransformMatrix = 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1/ + /Offset/ s/.*/& 0/ + /CenterOfRotation/ s/.*/& 0/ + s/AnatomicalOrientation = .*/AnatomicalOrientation = ????/ + /ElementSpacing/ s/.*/& 1/ + /DimSize/ s/.*/& $nbph/ + s/ElementDataFile = .*/ElementDataFile = LIST/" > CT_4D.mhd + +ls -1 *0.raw >> CT_4D.mhd +cd .. diff --git a/vv/scripts/create_sequence.sh b/vv/scripts/create_sequence.sh new file mode 100755 index 0000000..339d351 --- /dev/null +++ b/vv/scripts/create_sequence.sh @@ -0,0 +1,15 @@ +#!/bin/bash +#Create a sequence of mhd images from the various UNTAGGED directories +if [ $# -lt 1 ] +then + echo "Usage: create_sequence.sh prefix" + exit 1 +fi +for i in $1* +do + filename=CT_$1_$(echo "$i" | sed "s/.*,_//;s/\..*//").mhd + echo $filename + find "$i" -iname "*.dcm" | clitkDicom2Image --focal_origin -o "$filename" --std_input +done + +create_mhd_4D.sh . diff --git a/vv/scripts/dcm_sort_by_field.sh b/vv/scripts/dcm_sort_by_field.sh new file mode 100755 index 0000000..3ce4ec9 --- /dev/null +++ b/vv/scripts/dcm_sort_by_field.sh @@ -0,0 +1,32 @@ +#!/bin/bash +if [ $# -lt 1 ] +then + echo Usage: dcm_sort_by_field.sh \"field name\" + exit +fi +[ -d sorted ] && rm -r sorted +find . -type f -iname "*.dcm" > dicom_files +finished=0 +total=$(wc -l dicom_files) +mkdir sorted +cat dicom_files | while : +do + jobrunning=0 + conc_jobs=50 + while [ $jobrunning -lt $conc_jobs ] + do + read i || { wait; break 2; } + { + name="$(clitkDicomInfo "$i" | grep "$1" | sed "s/.*\[//;s/.$//;s/ /_/g")" + [ -z "$name" ] && echo "Warning: key not found in file $i" 1>&2 && exit 1 #don't do anything if dicom key not found + [ -d "sorted/$name" ] || mkdir "sorted/$name" 2>>/dev/null + basename=$(basename "$i") + cp -l "$i" "sorted/$name/$basename" + }& + jobrunning=$(( $jobrunning + 1 )) + done + finished=$(( $finished + $conc_jobs )) + echo -e -n "( $finished / $total )\r" + wait +done +rm dicom_files diff --git a/vv/scripts/dicom_info.sh b/vv/scripts/dicom_info.sh new file mode 100755 index 0000000..b18d7a5 --- /dev/null +++ b/vv/scripts/dicom_info.sh @@ -0,0 +1,3 @@ +#!/bin/bash +#Get info about the first dicom image in the directory +find . -iname "*.dcm" -type f | head -n1 | xargs clitkDicomInfo | less diff --git a/vv/scripts/transfer_patients.sh b/vv/scripts/transfer_patients.sh new file mode 100755 index 0000000..e683f7d --- /dev/null +++ b/vv/scripts/transfer_patients.sh @@ -0,0 +1,8 @@ +#!/bin/bash +cd current +echo -n "Patients before: " +find . -type l | wc -l +for i in /home/gauthier/Base_de_donnees_stereo_poumon/*; do [ -e "$i" ] || ln -s "$i" .; done +echo -n "Patients after: " +find . -type l | wc -l +for i in $(find . -type l); do date; echo $i; irsync -rv "$i" "i:/rhone-alpes/home/clb/patients/$i" >> "$i"_$(date "+%H:%m-%d_%b%Y").log; done diff --git a/vv/vtkVOXImageWriter.cxx b/vv/vtkVOXImageWriter.cxx new file mode 100644 index 0000000..0427f2f --- /dev/null +++ b/vv/vtkVOXImageWriter.cxx @@ -0,0 +1,158 @@ + +#include +#include + +#include "vtkVOXImageWriter.h" + +#include "vtkCommand.h" +#include "vtkErrorCode.h" +#include "vtkImageData.h" +#include "vtkInformation.h" +#include "vtkInformationVector.h" +#include "vtkObjectFactory.h" +#include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkDataSetAttributes.h" + +#include + +#include + +//---------------------------------------------------------------------------- +vtkCxxRevisionMacro(vtkVOXImageWriter, "$Revision: 1.1 $"); +vtkStandardNewMacro(vtkVOXImageWriter); + +//---------------------------------------------------------------------------- +vtkVOXImageWriter::vtkVOXImageWriter() +{ + this->FileName = 0; + this->FileLowerLeft = 1; +} + +//---------------------------------------------------------------------------- +vtkVOXImageWriter::~vtkVOXImageWriter() +{ + this->SetFileName(0); +} + + +//---------------------------------------------------------------------------- +void vtkVOXImageWriter::Write( ) +{ + this->SetErrorCode(vtkErrorCode::NoError); + + this->GetInput()->UpdateInformation(); + + // Error checking + if (this->GetInput() == NULL ) + { + vtkErrorMacro(<<"Write:Please specify an input!"); + return; + } + + if ( this->FileName == 0) + { + vtkErrorMacro("Output file name not specified"); + return; + } + + int nDims = 3; + int * ext = this->GetInput()->GetWholeExtent(); + if ( ext[4] == ext[5] ) + { + nDims = 2; + if ( ext[2] == ext[3] ) + { + nDims = 1; + } + } + + double * origin = this->GetInput()->GetOrigin(); + double * spacingDouble = this->GetInput()->GetSpacing(); + + float spacing[3]; + spacing[0] = spacingDouble[0]; + spacing[1] = spacingDouble[1]; + spacing[2] = spacingDouble[2]; + + int dimSize[3]; + dimSize[0] = ext[1]-ext[0]+1; + dimSize[1] = ext[3]-ext[2]+1; + dimSize[2] = ext[5]-ext[4]+1; + + std::string elementType; + + int scalarType = this->GetInput()->GetScalarType(); + switch ( scalarType ) + { + case VTK_CHAR: + elementType = "schar"; + break; + case VTK_UNSIGNED_CHAR: + elementType = "uchar"; + break; + case VTK_SHORT: + elementType = "sshort"; + break; + case VTK_UNSIGNED_SHORT: + elementType = "ushort"; + break; + case VTK_INT: + elementType = "int"; + break; + case VTK_UNSIGNED_INT: + elementType = "uint"; + break; + case VTK_LONG: + elementType = "slong"; + break; + case VTK_UNSIGNED_LONG: + elementType = "ulong"; + break; + case VTK_FLOAT: + elementType = "float"; + break; + case VTK_DOUBLE: + elementType = "double"; + break; + default: + vtkErrorMacro("Unknown scalar type." ); + return ; + } + + origin[0] += ext[0] * spacing[0]; + origin[1] += ext[2] * spacing[1]; + origin[2] += ext[4] * spacing[2]; + + this->GetInput()->SetUpdateExtent(ext[0], ext[1], + ext[2], ext[3], + ext[4], ext[5]); + this->GetInput()->UpdateData(); + + + this->SetFileDimensionality(nDims); + + this->InvokeEvent(vtkCommand::StartEvent); + this->UpdateProgress(0.0); + //write here + std::cout << "Writing to file " << this->GetFileName() << " ..." << std::endl; + std::cout.flush(); + fstream out(this->GetFileName(),ios::out|ios::binary); + out << "VOX v2\n# Size\n" << dimSize[0] << " " << dimSize[1] << " " + << dimSize[2] << std::endl << "# Spacing" << std::endl + << spacing[0] << " " << spacing[1] << " " << spacing[2] << std::endl + << "# Image dim" << std::endl << nDims << std::endl + << "# Image type" << std::endl << elementType << std::endl; + out.write((char*)this->GetInput()->GetScalarPointer(), + dimSize[0]*dimSize[1]*dimSize[2]*this->GetInput()->GetScalarSize()); + out.close(); + + this->UpdateProgress(1.0); + this->InvokeEvent(vtkCommand::EndEvent); +} + +//---------------------------------------------------------------------------- +void vtkVOXImageWriter::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); + os << indent << "FileName: " << (this->FileName==0?this->FileName:"(none)") << endl; +} diff --git a/vv/vtkVOXImageWriter.h b/vv/vtkVOXImageWriter.h new file mode 100644 index 0000000..4695e74 --- /dev/null +++ b/vv/vtkVOXImageWriter.h @@ -0,0 +1,36 @@ +#ifndef __vtkVoxImageWriter_h +#define __vtkVOXImageWriter_h + +#include "vtkImageWriter.h" +#include + + +class vtkVOXImageWriter : public vtkImageWriter +{ +public: + vtkTypeRevisionMacro(vtkVOXImageWriter,vtkImageWriter); + void PrintSelf(ostream& os, vtkIndent indent); + + // Description: + static vtkVOXImageWriter *New(); + + // Description: + // Specify file name of meta file + vtkSetStringMacro(FileName); + + // This is called by the superclass. + // This is the method you should override. + virtual void Write(); + +protected: + vtkVOXImageWriter(); + ~vtkVOXImageWriter(); + +private: + vtkVOXImageWriter(const vtkVOXImageWriter&); // Not implemented. + void operator=(const vtkVOXImageWriter&); // Not implemented. + + +}; + +#endif diff --git a/vv/vv.cxx b/vv/vv.cxx new file mode 100644 index 0000000..0896eae --- /dev/null +++ b/vv/vv.cxx @@ -0,0 +1,100 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vv.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#include +#include +#include +#include +#include +#include +#include + +#include "clitkCommon.h" +#include "vvMainWindow.h" +#include "vvInit.h" + +#include "vvConstants.h" + +int main( int argc, char** argv ) +{ + initialize_IO(); + + QApplication app( argc, argv ); + Q_INIT_RESOURCE(vvIcons); + //QPixmap pixmap(":/splashscreen.PNG"); + QSplashScreen *splash = new QSplashScreen(QPixmap(QString::fromUtf8(":/new/prefix1/splashscreen.PNG"))); + /*splash->showMessage("VV 1.0 developped by Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr and CREATIS-LRMN http://www.creatis.insa-lyon.fr",(Qt::AlignRight | Qt::AlignBottom));*/ +// splash->show(); + QTimer::singleShot(2000, splash, SLOT(close())); + while (!splash->isHidden()) + app.processEvents(); + + vvMainWindow window; + + //Try to give the window a sensible default size + int width=QApplication::desktop()->width()*0.8; + int height=QApplication::desktop()->height()*0.9; + if (width> 1.5*height) + width=1.5*height; + window.resize(width,height); + + window.show(); + + std::vector filenames; + std::vector > overlays; + std::vector > vector_fields; + if (argc >1) + { + for (int i = 1; i < argc; i++) + { + std::string temp = argv[i]; + if (temp=="--vf") + { + assert(filenames.size()>=1); + vector_fields.push_back(std::make_pair(filenames.size()-1,argv[i+1])); + i++; //skip vf name + } + else if (temp=="--overlay") + { + assert(filenames.size()>=1); + overlays.push_back(std::make_pair(filenames.size()-1,argv[i+1])); + i++; //skip overlay name + } + else + filenames.push_back(temp); + } + window.LoadImages(filenames,IMAGE); + for (std::vector >::iterator i=overlays.begin(); + i!=overlays.end();i++) + window.AddOverlayImage((*i).first,(*i).second.c_str()); + for (std::vector >::iterator i=vector_fields.begin(); + i!=vector_fields.end();i++) + window.AddField((*i).second.c_str(), (*i).first); + + } + + return app.exec(); +} diff --git a/vv/vvConstants.h b/vv/vvConstants.h new file mode 100644 index 0000000..efd2c74 --- /dev/null +++ b/vv/vvConstants.h @@ -0,0 +1,43 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvConstants.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:58 $ + Version: $Revision: 1.1 $ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvConstants_h +#define vvConstants_h + +//Constants used everywhere in the program + +//Image types +typedef enum _IMAGETYPE { +IMAGE = 20, +DICOM, +MERGED, +IMAGEWITHTIME, +MERGEDWITHTIME, +VECTORFIELD, +UNDEFINEDIMAGETYPE +} LoadedImageType; + +#endif diff --git a/vv/vvCropDialog.cxx b/vv/vvCropDialog.cxx new file mode 100644 index 0000000..af089dc --- /dev/null +++ b/vv/vvCropDialog.cxx @@ -0,0 +1,97 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include "vvCropDialog.h" +#include "vvSlicerManager.h" +#include "clitkCommon.h" + +vvCropDialog::vvCropDialog(std::vector sms,int current) : + mSlicerManagers(sms) +{ + setupUi(this); + for (unsigned int i=0;iaddItem(vtksys::SystemTools::GetFilenameName(mSlicerManagers[i]->GetFileName()).c_str()); + connect(inputSequenceBox,SIGNAL(currentIndexChanged(int)),this,SLOT(ImageChanged(int))); + inputSequenceBox->setCurrentIndex(current); + ImageChanged(current); + connect(this,SIGNAL(accepted()),this,SLOT(ComputeCroppedImage())); +} + +void vvCropDialog::ImageChanged(int newindex) +{ + std::vector imsize=mSlicerManagers[newindex]->GetImage()->GetSize(); + xminSlider->setMaximum(imsize[0]-1); + xmaxSlider->setMaximum(imsize[0]-1); + xmaxSlider->setValue(imsize[0]-1); + yminSlider->setMaximum(imsize[1]-1); + ymaxSlider->setMaximum(imsize[1]-1); + ymaxSlider->setValue(imsize[1]-1); + zminSlider->setMaximum(imsize[2]-1); + zmaxSlider->setMaximum(imsize[2]-1); + zmaxSlider->setValue(imsize[2]-1); + spin_xmin->setMaximum(imsize[0]-1); + spin_xmax->setMaximum(imsize[0]-1); + spin_xmax->setValue(imsize[0]-1); + spin_ymin->setMaximum(imsize[1]-1); + spin_ymax->setMaximum(imsize[1]-1); + spin_ymax->setValue(imsize[1]-1); + spin_zmin->setMaximum(imsize[2]-1); + spin_zmax->setMaximum(imsize[2]-1); + spin_zmax->setValue(imsize[2]-1); +} + +void vvCropDialog::ComputeCroppedImage() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + mResult=vvImage::New(); + vvSlicerManager * current=mSlicerManagers[inputSequenceBox->currentIndex()]; + vvImage::Pointer image=current->GetImage(); + for (std::vector::const_iterator i=image->GetVTKImages().begin(); + i!=image->GetVTKImages().end();i++) + { + vtkSmartPointer filter=vtkSmartPointer::New(); + ///Vtk is very weird, you need to "translate the extent" to get the correct origin + //http://markmail.org/message/vndc2tr6kcabiakp#query:vtkImageClip%20origin+page:1+mid:6na7y57floutklvz+state:results + vtkSmartPointer translate=vtkSmartPointer::New(); + filter->SetInput(*i); + filter->SetOutputWholeExtent(xminSlider->value(),xmaxSlider->value(), + yminSlider->value(),ymaxSlider->value(), + zminSlider->value(),zmaxSlider->value()); + translate->SetTranslation(-xminSlider->value(),-yminSlider->value(),-zminSlider->value()); + translate->SetInput(filter->GetOutput()); + filter->ClipDataOn(); //Really create a cropped copy of the image + translate->Update(); + vtkImageData* output=vtkImageData::New(); + output->ShallowCopy(translate->GetOutput()); + mResult->AddImage(output); + } + QApplication::restoreOverrideCursor(); +} diff --git a/vv/vvCropDialog.h b/vv/vvCropDialog.h new file mode 100644 index 0000000..e052df1 --- /dev/null +++ b/vv/vvCropDialog.h @@ -0,0 +1,51 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + Program: vv + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvCropDialog_h +#define vvCropDialog_h + +#include +#include +class vvSlicerManager; +#include "vvImage.h" +#include "ui_vvCropDialog.h" + +///Allows the user to create a new image by cropping an existing one +class vvCropDialog : public QDialog,private Ui::vvCropDialog +{ + Q_OBJECT +public: + vvCropDialog(std::vector sms,int current=0); + vvImage::Pointer GetOutput() {return mResult;} + +protected: + std::vector mSlicerManagers; + vvImage::Pointer mResult; + +private slots: + void ImageChanged(int newindex); + void ComputeCroppedImage(); +}; + +#endif diff --git a/vv/vvDeformableRegistration.cxx b/vv/vvDeformableRegistration.cxx new file mode 100644 index 0000000..e5f861c --- /dev/null +++ b/vv/vvDeformableRegistration.cxx @@ -0,0 +1,180 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "vtkVOXImageWriter.h" +#include + +#include "clitkCommon.h" +#include "vvSlicerManager.h" +#include "vvDeformableRegistration.h" +#include "vvImage.h" +#include "vvImage.h" +#include "vvImageReader.h" + +vvDeformableRegistration::vvDeformableRegistration(vvImage::Pointer image,unsigned int ref,\ + unsigned int iter, unsigned int nthread,double a, double s,std::string output_f,unsigned int stop) : + mImage(image), + refimage(ref), + nb_iter(iter), + n_thread(nthread), + progress(0), + stop(stop), + alpha(a), + sigma(s), + output_filename(output_f), + aborted(false) +{ +} + +void vvDeformableRegistration::abort() +{ + aborted=true; + std::system("killall deformableregistration"); + std::system("killall clitkVFMerge"); +} + +unsigned int vvDeformableRegistration::getProgress() +{ + QMutexLocker locker(&progress_mutex); + unsigned int retval=progress; + return retval; +} + +void vvDeformableRegistration::cleanup(int frame_number) //remove temporary files +{ + std::string temp_dir=mTempPath.toStdString(); + for (int i=0;iapplicationPid()); + QDir temp_qt_dir; + DD(temp_qt_dir.mkpath(mTempPath)); + std::string temp_dir=mTempPath.toStdString(); + DD(temp_dir); + std::vector images=mImage->GetVTKImages(); + for (unsigned int i=0;iSetInput(images[i]); + vox->SetFileName(filename.str().c_str()); + if (i==refimage) + ref_file=filename.str(); + vox->Write(); + } + vox->Delete(); + progress++; + int reg_per_thread=static_cast(images.size()-1)/n_thread; + int remainder=static_cast(images.size()-1) - reg_per_thread*n_thread; +#pragma omp parallel for num_threads(n_thread) schedule(static) + for (int i=0;i(n_thread);i++) + { + ///Static scheduling + int remainder_shift=((iGetOrigin()[0]; + command << " --yorigin " << images[0]->GetOrigin()[1]; + command << " --zorigin " << images[0]->GetOrigin()[2]; + command << " -o " << output_filename << std::endl; + DD(command.str()); + std::system(command.str().c_str()); + cleanup(images.size()); + if (aborted) + { + std::system(("rm " + output_filename).c_str()); + return; + } + vvImageReader reader; + reader.SetInputFilename(output_filename); + reader.Update(VECTORFIELD); + finish=clock(); + DD((finish - start)/static_cast(CLOCKS_PER_SEC)); + mOutput=reader.GetOutput(); +} diff --git a/vv/vvDeformableRegistration.h b/vv/vvDeformableRegistration.h new file mode 100644 index 0000000..71910b6 --- /dev/null +++ b/vv/vvDeformableRegistration.h @@ -0,0 +1,39 @@ +#ifndef VV_DEFORMABLE_REGISTRATION +#define VV_DEFORMABLE_REGISTRATION + +#include +#include +class string; +class QThread; +class vvImage; +#include "vvImage.h" + +class vvDeformableRegistration : public QThread +{ +public: + vvDeformableRegistration(vvImage::Pointer image,unsigned int ref,\ + unsigned int iter, unsigned int nthread,double a, double s,\ + std::string output_f,unsigned int stop); + unsigned int getProgress(); + void abort(); + QMutex progress_mutex; + void run(); + vvImage::Pointer getOutput() { + return mOutput; + } +protected: + vvImage::Pointer mImage; + vvImage::Pointer mOutput; + unsigned int refimage,nb_iter,n_thread,progress,stop; + double alpha,sigma; + std::string output_filename; + bool aborted; + void cleanup(int); + void partial_run(int,int,int,std::string); + ///Temporary path, specific to the current instance of vv + QString mTempPath; +}; + + +#endif + diff --git a/vv/vvDeformationDialog.cxx b/vv/vvDeformationDialog.cxx new file mode 100644 index 0000000..5dda22d --- /dev/null +++ b/vv/vvDeformationDialog.cxx @@ -0,0 +1,144 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#include +#include + +#include "clitkCommon.h" + +#include "vvDeformationDialog.h" +#include "vvDeformableRegistration.h" +#include "vvSlicer.h" +#include "vvToITK.h" +#include "vvFromITK.h" +#include "vvSlicerManager.h" + +vvSlicerManager * vvDeformationDialog::GetSelectedSlicer() const +{ + return mSlicerManagers[inputSequenceBox->currentIndex()]; +} + +int vvDeformationDialog::GetReferenceFrameIndex() const +{ + return refImageSlider->value(); +} + +vvDeformationDialog::vvDeformationDialog(int initialSlicer,const std::vector& slicerManagers) + : mSlicerManagers(slicerManagers) +{ + setupUi(this); + connect(this,SIGNAL(accepted()),this,SLOT(computeDeformationField())); + for (unsigned int i=0;iaddItem(vtksys::SystemTools::GetFilenameName(slicerManagers[i]->GetFileName()).c_str()); + connect(inputSequenceBox,SIGNAL(currentIndexChanged(int)),this,SLOT(resetSlider(int))); + connect(refImageSlider,SIGNAL(valueChanged(int)),this,SLOT(updateSliderLabel(int))); + connect(outputPushButton, SIGNAL(clicked()), this, SLOT(selectOutputFile())); + inputSequenceBox->setCurrentIndex(initialSlicer); + resetSlider(initialSlicer); + + //Compute ideal number of threads and update dialog accordingly + int best_thread=QThread::idealThreadCount(); + threadSpin->setValue(best_thread); + +} + +void vvDeformationDialog::selectOutputFile() +{ + QString Extensions = "MHD Images( *.mhd);;"; + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save As"), + itksys::SystemTools::GetFilenamePath( + mSlicerManagers[inputSequenceBox->currentIndex()]->GetFileName()).c_str(), + Extensions); + outputLineEdit->setText(fileName); +} + +void vvDeformationDialog::updateSliderLabel(int refimage) +{ + QString count; + count.setNum(refimage); //Normal people start counting at 1... + QString newlabel="Reference Image ("; + newlabel+=count; + newlabel+=")"; + refImageLabel->setText(newlabel); +} + +void vvDeformationDialog::resetSlider(int slicer_index) +{ + refImageSlider->setRange(0,mSlicerManagers[slicer_index]->GetSlicer(0)->GetImage()->GetSize()[3]-1); + int refimage=mSlicerManagers[slicer_index]->GetSlicer(0)->GetTSlice(); + refImageSlider->setSliderPosition(refimage); + updateSliderLabel(refimage); +} + +void vvDeformationDialog::computeDeformationField() { + vvImage::Pointer sequence=mSlicerManagers[inputSequenceBox->currentIndex()]->GetSlicer(0)->GetImage(); + vtkImageData * first_image = sequence->GetVTKImages()[0]; + if (not sequence->IsTimeSequence()) + { + this->setResult(QDialog::Rejected); + QMessageBox::warning(this,tr("Image type error"), tr("Deformable image registration only makes sense on time sequences.")); + } + else if ((first_image->GetSpacing()[0] != first_image->GetSpacing()[1]) or (first_image->GetSpacing()[0] != first_image->GetSpacing()[2])) + { + this->setResult(QDialog::Rejected); + QMessageBox::warning(this,tr("Image type error"), tr("Deformable registration only works well with isotropic voxels. Please resample the image.")); + return; + } + else { + bool aborted=false; + QProgressDialog progress(this); + QProgressDialog cancel(this); + cancel.setLabelText("Canceling, please wait..."); + cancel.setCancelButtonText(0); + cancel.hide(); + //1 step per registration plus one for each of the image conversions + progress.setMaximum(mSlicerManagers[inputSequenceBox->currentIndex()] + ->GetSlicer(0)->GetImage()->GetSize()[3]+2); + progress.setLabelText("Computing deformation model..."); + progress.setMinimumDuration(0); + progress.setWindowModality(Qt::WindowModal); + progress.setCancelButtonText("Cancel"); + qApp->processEvents(); + QFileInfo info(outputLineEdit->text().toStdString().c_str()); + if (info.isRelative()) //this is a bit hackish, but should work + { + QFileInfo im_info(mSlicerManagers[inputSequenceBox->currentIndex()]->GetFileName().c_str()); + outputLineEdit->setText((im_info.path().toStdString() + "/" + outputLineEdit->text().toStdString()).c_str()); + } + vvDeformableRegistration registrator(sequence,refImageSlider->value(), iterSpin->value(),threadSpin->value(), alphaSpin->value(), sigmaSpin->value(),outputLineEdit->text().toStdString(),stopSpin->value()); + registrator.start(); + while (!registrator.isFinished()) + { + if (progress.wasCanceled() and not aborted) + { + this->setResult(QDialog::Rejected); + registrator.abort(); + aborted=true; + progress.hide(); + cancel.show(); + } + if (!aborted) + progress.setValue(registrator.getProgress()); + qApp->processEvents(); + registrator.wait(50); + } + if (not aborted) + { + mOutput=registrator.getOutput(); + } + } +} diff --git a/vv/vvDeformationDialog.h b/vv/vvDeformationDialog.h new file mode 100644 index 0000000..f527d17 --- /dev/null +++ b/vv/vvDeformationDialog.h @@ -0,0 +1,43 @@ +#ifndef VV_DEFORMATION_DIALOG +#define VV_DEFORMATION_DIALOG + +#include +#include +#include +class vvSlicerManager; +#include +#include "ui_vvDeformationDialog.h" + +class vvDeformationDialog : public QDialog, private Ui::vvDeformationDialog +{ + Q_OBJECT + +public: + vvDeformationDialog(int initialSlicer,const std::vector& slicerManagers); + int GetInputFileIndex() const { + return inputSequenceBox->currentIndex(); + } + QString getFieldFile() const { + return outputLineEdit->text(); + } + vvImage::Pointer GetOutput() { + return mOutput; + } + vvSlicerManager * GetSelectedSlicer() const; + int GetReferenceFrameIndex() const; + +private slots: + void computeDeformationField(); + void updateSliderLabel(int refimage); + void resetSlider(int slicer_index); + void selectOutputFile(); +protected: + template void Update_WithDim(); + template void Update_WithDimAndPixelType(); + std::vector mSlicerManagers; + vvImage::Pointer mOutput; +}; + + + +#endif diff --git a/vv/vvDocumentation.h b/vv/vvDocumentation.h new file mode 100644 index 0000000..f997613 --- /dev/null +++ b/vv/vvDocumentation.h @@ -0,0 +1,51 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvDocumentation.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvDocumentation_h +#define vvDocumentation_h + +#include +#include + +#include "ui_vvDocumentation.h" + +class vvDocumentation : public QDialog, private Ui::vvDocumentation +{ + Q_OBJECT + +public: + vvDocumentation() { + setupUi(this); + } + ~vvDocumentation() {} + +public slots: + +private: + +}; + +#endif diff --git a/vv/vvGlyph2D.cxx b/vv/vvGlyph2D.cxx new file mode 100644 index 0000000..dfb64e0 --- /dev/null +++ b/vv/vvGlyph2D.cxx @@ -0,0 +1,647 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvGlyph2D.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#include "vvGlyph2D.h" + +#include "vtkCell.h" +#include "vtkDataSet.h" +#include "vtkFloatArray.h" +#include "vtkIdList.h" +#include "vtkIdTypeArray.h" +#include "vtkInformation.h" +#include "vtkInformationVector.h" +#include "vtkMath.h" +#include "vtkObjectFactory.h" +#include "vtkPointData.h" +#include "vtkPolyData.h" +#include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkTransform.h" +#include "vtkUnsignedCharArray.h" + +vtkCxxRevisionMacro(vvGlyph2D, "$Revision: 1.1 $"); +vtkStandardNewMacro(vvGlyph2D); + +vvGlyph2D::vvGlyph2D() +{ + mOrientation[0] = 1; + mOrientation[1] = 1; + mOrientation[2] = 1; + mUseLog = 0; +} + +//---------------------------------------------------------------------------- +int vvGlyph2D::RequestData( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **inputVector, + vtkInformationVector *outputVector) +{ + // get the info objects + vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); + vtkInformation *outInfo = outputVector->GetInformationObject(0); + + // get the input and ouptut + vtkDataSet *input = vtkDataSet::SafeDownCast( + inInfo->Get(vtkDataObject::DATA_OBJECT())); + vtkPolyData *output = vtkPolyData::SafeDownCast( + outInfo->Get(vtkDataObject::DATA_OBJECT())); + + vtkPointData *pd; + vtkDataArray *inSScalars; // Scalars for Scaling + vtkDataArray *inCScalars; // Scalars for Coloring + vtkDataArray *inVectors; + int requestedGhostLevel; + unsigned char* inGhostLevels=0; + vtkDataArray *inNormals, *sourceNormals = NULL; + vtkDataArray *sourceTCoords = NULL; + vtkIdType numPts, numSourcePts, numSourceCells, inPtId, i; + int index; + vtkPoints *sourcePts = NULL; + vtkPoints *newPts; + vtkDataArray *newScalars=NULL; + vtkDataArray *newVectors=NULL; + vtkDataArray *newNormals=NULL; + vtkDataArray *newTCoords = NULL; + double x[3], v[3], vNew[3], s = 0.0, vMag = 0.0, value, tc[3]; + vtkTransform *trans = vtkTransform::New(); + vtkCell *cell; + vtkIdList *cellPts; + int npts; + vtkIdList *pts; + vtkIdType ptIncr, cellId; + int haveVectors, haveNormals, haveTCoords = 0; + double scalex,scaley,scalez, den; + vtkPointData *outputPD = output->GetPointData(); + int numberOfSources = this->GetNumberOfInputConnections(1); + vtkPolyData *defaultSource = NULL; + vtkIdTypeArray *pointIds=0; + vtkPolyData *source = 0; + + vtkDebugMacro(<<"Generating glyphs"); + + pts = vtkIdList::New(); + pts->Allocate(VTK_CELL_SIZE); + + pd = input->GetPointData(); + inSScalars = this->GetInputArrayToProcess(0,inputVector); + inVectors = this->GetInputArrayToProcess(1,inputVector); + inNormals = this->GetInputArrayToProcess(2,inputVector); + inCScalars = this->GetInputArrayToProcess(3,inputVector); + if (inCScalars == NULL) + { + inCScalars = inSScalars; + } + + vtkDataArray* temp = 0; + if (pd) + { + temp = pd->GetArray("vtkGhostLevels"); + } + if ( (!temp) || (temp->GetDataType() != VTK_UNSIGNED_CHAR) + || (temp->GetNumberOfComponents() != 1)) + { + vtkDebugMacro("No appropriate ghost levels field available."); + } + else + { + inGhostLevels = ((vtkUnsignedCharArray*)temp)->GetPointer(0); + } + + requestedGhostLevel = + outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS()); + + numPts = input->GetNumberOfPoints(); + if (numPts < 1) + { + vtkDebugMacro(<<"No points to glyph!"); + pts->Delete(); + trans->Delete(); + return 1; + } + + // Check input for consistency + // + if ( (den = this->Range[1] - this->Range[0]) == 0.0 ) + { + den = 1.0; + } + if ( this->VectorMode != VTK_VECTOR_ROTATION_OFF && + ((this->VectorMode == VTK_USE_VECTOR && inVectors != NULL) || + (this->VectorMode == VTK_USE_NORMAL && inNormals != NULL)) ) + { + haveVectors = 1; + } + else + { + haveVectors = 0; + } + + if ( (this->IndexMode == VTK_INDEXING_BY_SCALAR && !inSScalars) || + (this->IndexMode == VTK_INDEXING_BY_VECTOR && + ((!inVectors && this->VectorMode == VTK_USE_VECTOR) || + (!inNormals && this->VectorMode == VTK_USE_NORMAL))) ) + { + if ( this->GetSource(0, inputVector[1]) == NULL ) + { + vtkErrorMacro(<<"Indexing on but don't have data to index with"); + pts->Delete(); + trans->Delete(); + return 1; + } + else + { + vtkWarningMacro(<<"Turning indexing off: no data to index with"); + this->IndexMode = VTK_INDEXING_OFF; + } + } + + // Allocate storage for output PolyData + // + outputPD->CopyVectorsOff(); + outputPD->CopyNormalsOff(); + outputPD->CopyTCoordsOff(); + + if (!this->GetSource(0, inputVector[1])) + { + defaultSource = vtkPolyData::New(); + defaultSource->Allocate(); + vtkPoints *defaultPoints = vtkPoints::New(); + defaultPoints->Allocate(6); + defaultPoints->InsertNextPoint(0, 0, 0); + defaultPoints->InsertNextPoint(1, 0, 0); + vtkIdType defaultPointIds[2]; + defaultPointIds[0] = 0; + defaultPointIds[1] = 1; + defaultSource->SetPoints(defaultPoints); + defaultSource->InsertNextCell(VTK_LINE, 2, defaultPointIds); + defaultSource->SetUpdateExtent(0, 1, 0); + this->SetSource(defaultSource); + defaultSource->Delete(); + defaultSource = NULL; + defaultPoints->Delete(); + defaultPoints = NULL; + } + + if ( this->IndexMode != VTK_INDEXING_OFF ) + { + pd = NULL; + haveNormals = 1; + for (numSourcePts=numSourceCells=i=0; i < numberOfSources; i++) + { + source = this->GetSource(i, inputVector[1]); + if ( source != NULL ) + { + if (source->GetNumberOfPoints() > numSourcePts) + { + numSourcePts = source->GetNumberOfPoints(); + } + if (source->GetNumberOfCells() > numSourceCells) + { + numSourceCells = source->GetNumberOfCells(); + } + if ( !(sourceNormals = source->GetPointData()->GetNormals()) ) + { + haveNormals = 0; + } + } + } + } + else + { + source = this->GetSource(0, inputVector[1]); + sourcePts = source->GetPoints(); + numSourcePts = sourcePts->GetNumberOfPoints(); + numSourceCells = source->GetNumberOfCells(); + + sourceNormals = source->GetPointData()->GetNormals(); + if ( sourceNormals ) + { + haveNormals = 1; + } + else + { + haveNormals = 0; + } + + sourceTCoords = source->GetPointData()->GetTCoords(); + if (sourceTCoords) + { + haveTCoords = 1; + } + else + { + haveTCoords = 0; + } + + // Prepare to copy output. + pd = input->GetPointData(); + outputPD->CopyAllocate(pd,numPts*numSourcePts); + } + + newPts = vtkPoints::New(); + newPts->Allocate(numPts*numSourcePts); + if ( this->GeneratePointIds ) + { + pointIds = vtkIdTypeArray::New(); + pointIds->SetName(this->PointIdsName); + pointIds->Allocate(numPts*numSourcePts); + outputPD->AddArray(pointIds); + pointIds->Delete(); + } + if ( this->ColorMode == VTK_COLOR_BY_SCALAR && inCScalars ) + { + newScalars = inCScalars->NewInstance(); + newScalars->SetNumberOfComponents(inCScalars->GetNumberOfComponents()); + newScalars->Allocate(inCScalars->GetNumberOfComponents()*numPts*numSourcePts); + newScalars->SetName(inCScalars->GetName()); + } + else if ( (this->ColorMode == VTK_COLOR_BY_SCALE) && inSScalars) + { + newScalars = vtkFloatArray::New(); + newScalars->Allocate(numPts*numSourcePts); + newScalars->SetName("GlyphScale"); + if (this->ScaleMode == VTK_SCALE_BY_SCALAR) + { + newScalars->SetName(inSScalars->GetName()); + } + } + else if ( (this->ColorMode == VTK_COLOR_BY_VECTOR) && haveVectors) + { + newScalars = vtkFloatArray::New(); + newScalars->Allocate(numPts*numSourcePts); + newScalars->SetName("VectorMagnitude"); + } + if ( haveVectors ) + { + newVectors = vtkFloatArray::New(); + newVectors->SetNumberOfComponents(3); + newVectors->Allocate(3*numPts*numSourcePts); + newVectors->SetName("GlyphVector"); + } + if ( haveNormals ) + { + newNormals = vtkFloatArray::New(); + newNormals->SetNumberOfComponents(3); + newNormals->Allocate(3*numPts*numSourcePts); + newNormals->SetName("Normals"); + } + if (haveTCoords) + { + newTCoords = vtkFloatArray::New(); + int numComps = sourceTCoords->GetNumberOfComponents(); + newTCoords->SetNumberOfComponents(numComps); + newTCoords->Allocate(numComps*numPts*numSourcePts); + newTCoords->SetName("TCoords"); + } + + // Setting up for calls to PolyData::InsertNextCell() + if (this->IndexMode != VTK_INDEXING_OFF ) + { + output->Allocate(3*numPts*numSourceCells,numPts*numSourceCells); + } + else + { + output->Allocate(this->GetSource(0, inputVector[1]), + 3*numPts*numSourceCells, numPts*numSourceCells); + } + + // Traverse all Input points, transforming Source points and copying + // point attributes. + // + ptIncr=0; + for (inPtId=0; inPtId < numPts; inPtId++) + { + scalex = scaley = scalez = 1.0; + if ( ! (inPtId % 10000) ) + { + this->UpdateProgress ((double)inPtId/numPts); + if (this->GetAbortExecute()) + { + break; + } + } + + // Get the scalar and vector data + if ( inSScalars ) + { + s = inSScalars->GetComponent(inPtId, 0); + if ( this->ScaleMode == VTK_SCALE_BY_SCALAR || + this->ScaleMode == VTK_DATA_SCALING_OFF ) + { + scalex = scaley = scalez = s; + } + } + + if ( haveVectors ) + { + if ( this->VectorMode == VTK_USE_NORMAL ) + { + inNormals->GetTuple(inPtId, v); + } + else + { + inVectors->GetTuple(inPtId, v); + } + + vMag = vtkMath::Norm(v); + if ( this->ScaleMode == VTK_SCALE_BY_VECTORCOMPONENTS ) + { + scalex = v[0]; + scaley = v[1]; + scalez = v[2]; + } + else if ( this->ScaleMode == VTK_SCALE_BY_VECTOR ) + { + scalex = scaley = scalez = vMag; + } + } + + // Clamp data scale if enabled + if ( this->Clamping ) + { + scalex = (scalex < this->Range[0] ? this->Range[0] : + (scalex > this->Range[1] ? this->Range[1] : scalex)); + scalex = (scalex - this->Range[0]) / den; + scaley = (scaley < this->Range[0] ? this->Range[0] : + (scaley > this->Range[1] ? this->Range[1] : scaley)); + scaley = (scaley - this->Range[0]) / den; + scalez = (scalez < this->Range[0] ? this->Range[0] : + (scalez > this->Range[1] ? this->Range[1] : scalez)); + scalez = (scalez - this->Range[0]) / den; + } + + // Compute index into table of glyphs + if ( this->IndexMode == VTK_INDEXING_OFF ) + { + index = 0; + } + else + { + if ( this->IndexMode == VTK_INDEXING_BY_SCALAR ) + { + value = s; + } + else + { + value = vMag; + } + + index = (int) ((double)(value - this->Range[0]) * numberOfSources / den); + index = (index < 0 ? 0 : + (index >= numberOfSources ? (numberOfSources-1) : index)); + + source = this->GetSource(index, inputVector[1]); + if ( source != NULL ) + { + sourcePts = source->GetPoints(); + sourceNormals = source->GetPointData()->GetNormals(); + numSourcePts = sourcePts->GetNumberOfPoints(); + numSourceCells = source->GetNumberOfCells(); + } + } + + // Make sure we're not indexing into empty glyph + if ( this->GetSource(index, inputVector[1]) == NULL ) + { + continue; + } + + // Check ghost points. + // If we are processing a piece, we do not want to duplicate + // glyphs on the borders. The corrct check here is: + // ghostLevel > 0. I am leaving this over glyphing here because + // it make a nice example (sphereGhost.tcl) to show the + // point ghost levels with the glyph filter. I am not certain + // of the usefullness of point ghost levels over 1, but I will have + // to think about it. + if (inGhostLevels && inGhostLevels[inPtId] > requestedGhostLevel) + { + continue; + } + + if (!this->IsPointVisible(input, inPtId)) + { + continue; + } + + // Now begin copying/transforming glyph + trans->Identity(); + + // Copy all topology (transformation independent) + for (cellId=0; cellId < numSourceCells; cellId++) + { + cell = this->GetSource(index, inputVector[1])->GetCell(cellId); + cellPts = cell->GetPointIds(); + npts = cellPts->GetNumberOfIds(); + for (pts->Reset(), i=0; i < npts; i++) + { + pts->InsertId(i,cellPts->GetId(i) + ptIncr); + } + output->InsertNextCell(cell->GetCellType(),pts); + } + + // translate Source to Input point + input->GetPoint(inPtId, x); + + //projection on the plane orthogonale to the camera + trans->Scale(mOrientation[0],mOrientation[1],mOrientation[2]); + + trans->Translate(x[0], x[1], x[2]); + + if ( haveVectors ) + { + // Copy Input vector + for (i=0; i < numSourcePts; i++) + { + newVectors->InsertTuple(i+ptIncr, v); + } + if (this->Orient && (vMag > 0.0)) + { + // if there is no y or z component + if ( v[1] == 0.0 && v[2] == 0.0 ) + { + if (v[0] < 0) //just flip x if we need to + { + trans->RotateWXYZ(180.0,0,1,0); + } + } + else + { + vNew[0] = (v[0]+vMag) / 2.0; + vNew[1] = v[1] / 2.0; + vNew[2] = v[2] / 2.0; + trans->RotateWXYZ((double)180.0,vNew[0],vNew[1],vNew[2]); + } + } + } + + if (haveTCoords) + { + for (i = 0; i < numSourcePts; i++) + { + sourceTCoords->GetTuple(i, tc); + newTCoords->InsertTuple(i+ptIncr, tc); + } + } + + // determine scale factor from scalars if appropriate + // Copy scalar value + if (inSScalars && (this->ColorMode == VTK_COLOR_BY_SCALE)) + { + for (i=0; i < numSourcePts; i++) + { + newScalars->InsertTuple(i+ptIncr, &scalex); // = scaley = scalez + } + } + else if (inCScalars && (this->ColorMode == VTK_COLOR_BY_SCALAR)) + { + for (i=0; i < numSourcePts; i++) + { + outputPD->CopyTuple(inCScalars, newScalars, inPtId, ptIncr+i); + } + } + if (haveVectors && this->ColorMode == VTK_COLOR_BY_VECTOR) + { + double color = 1; + for (i=0; i < numSourcePts; i++) + { + newScalars->InsertTuple(i+ptIncr, &color); + } + } + + // scale data if appropriate + if ( this->Scaling ) + { + if ( this->ScaleMode == VTK_DATA_SCALING_OFF ) + { + scalex = scaley = scalez = this->ScaleFactor; + } + else + { + scalex *= this->ScaleFactor; + scaley *= this->ScaleFactor; + scalez *= this->ScaleFactor; + } + + if ( scalex == 0.0 ) + { + scalex = 1.0e-10; + } + if ( scaley == 0.0 ) + { + scaley = 1.0e-10; + } + if ( scalez == 0.0 ) + { + scalez = 1.0e-10; + } + trans->Scale(scalex,scaley,scalez); + } + // multiply points and normals by resulting matrix + trans->TransformPoints(sourcePts,newPts); + + if ( haveNormals ) + { + trans->TransformNormals(sourceNormals,newNormals); + } + + // Copy point data from source (if possible) + if ( pd ) + { + for (i=0; i < numSourcePts; i++) + { + outputPD->CopyData(pd,inPtId,ptIncr+i); + } + } + + // If point ids are to be generated, do it here + if ( this->GeneratePointIds ) + { + for (i=0; i < numSourcePts; i++) + { + pointIds->InsertNextValue(inPtId); + } + } + + ptIncr += numSourcePts; + } + + // Update ourselves and release memory + // + output->SetPoints(newPts); + newPts->Delete(); + + if (newScalars) + { + int idx = outputPD->AddArray(newScalars); + outputPD->SetActiveAttribute(idx, vtkDataSetAttributes::SCALARS); + newScalars->Delete(); + } + + if (newVectors) + { + outputPD->SetVectors(newVectors); + newVectors->Delete(); + } + + if (newNormals) + { + outputPD->SetNormals(newNormals); + newNormals->Delete(); + } + + if (newTCoords) + { + outputPD->SetTCoords(newTCoords); + newTCoords->Delete(); + } + + output->Squeeze(); + trans->Delete(); + pts->Delete(); + + return 1; +} + +void vvGlyph2D::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); +} + +void vvGlyph2D::SetOrientation(int x, int y, int z) +{ + if (x == 0) + mOrientation[0] = 1.0e-10; + else + mOrientation[0] = 1.0; + if (y == 0) + mOrientation[1] = 1.0e-10; + else + mOrientation[1] = 1.0; + if (z == 0) + mOrientation[2] = 1.0e-10; + else + mOrientation[2] = 1.0; +} diff --git a/vv/vvGlyph2D.h b/vv/vvGlyph2D.h new file mode 100644 index 0000000..611f21f --- /dev/null +++ b/vv/vvGlyph2D.h @@ -0,0 +1,67 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvGlyph2D.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#ifndef __vvGlyph2D_h +#define __vvGlyph2D_h + +#include "vtkGlyph3D.h" + +class vvGlyph2D : public vtkGlyph3D +{ +public: + vtkTypeRevisionMacro(vvGlyph2D,vtkGlyph3D); + void PrintSelf(ostream& os, vtkIndent indent); + + // Description + // Construct object with scaling on, scaling mode is by scalar value, + // scale factor = 1.0, the range is (0,1), orient geometry is on, and + // orientation is by vector. Clamping and indexing are turned off. No + // initial sources are defined. + void SetOrientation(int x,int y,int z); + static vvGlyph2D *New(); + + void SetUseLog(int log) { + mUseLog = log; + } + int GetUseLog() { + return mUseLog; + } + +protected: + vvGlyph2D(); + ~vvGlyph2D() {}; + + virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); + +private: + vvGlyph2D(const vvGlyph2D&); // Not implemented. + void operator=(const vvGlyph2D&); // Not implemented. + double mOrientation[3]; + int mUseLog; +}; + +#endif diff --git a/vv/vvGlyphSource.cxx b/vv/vvGlyphSource.cxx new file mode 100644 index 0000000..3900310 --- /dev/null +++ b/vv/vvGlyphSource.cxx @@ -0,0 +1,178 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvGlyphSource.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#include "vvGlyphSource.h" + +#include "vtkCellArray.h" +#include "vtkCellData.h" +#include "vtkMath.h" +#include "vtkInformation.h" +#include "vtkInformationVector.h" +#include "vtkObjectFactory.h" +#include "vtkPolyData.h" +#include "vtkUnsignedCharArray.h" + +vtkCxxRevisionMacro(vvGlyphSource, "$Revision: 1.1 $"); +vtkStandardNewMacro(vvGlyphSource); + + +//---------------------------------------------------------------------------- +int vvGlyphSource::RequestData( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **vtkNotUsed(inputVector), + vtkInformationVector *outputVector) +{ + // get the info object + vtkInformation *outInfo = outputVector->GetInformationObject(0); + + // get the ouptut + vtkPolyData *output = vtkPolyData::SafeDownCast( + outInfo->Get(vtkDataObject::DATA_OBJECT())); + + //Allocate storage + vtkPoints *pts = vtkPoints::New(); + pts->Allocate(6,6); + vtkCellArray *verts = vtkCellArray::New(); + verts->Allocate(verts->EstimateSize(1,1),1); + vtkCellArray *lines = vtkCellArray::New(); + lines->Allocate(lines->EstimateSize(4,2),2); + vtkCellArray *polys = vtkCellArray::New(); + polys->Allocate(polys->EstimateSize(1,4),4); + vtkUnsignedCharArray *colors = vtkUnsignedCharArray::New(); + colors->SetNumberOfComponents(3); + colors->Allocate(2,2); + + this->ConvertColor(); + + //Special options + if ( this->Dash ) + { + int filled = this->Filled; + this->Filled = 0; + this->CreateDash(pts,lines,polys,colors,this->Scale2); + this->Filled = filled; + } + if ( this->Cross ) + { + int filled = this->Filled; + this->Filled = 0; + this->CreateCross(pts,lines,polys,colors,this->Scale2); + this->Filled = filled; + } + + //Call the right function + switch (this->GlyphType) + { + case VTK_NO_GLYPH: + break; + case VTK_VERTEX_GLYPH: + this->CreateVertex(pts,verts,colors); + break; + case VTK_DASH_GLYPH: + this->CreateDash(pts,lines,polys,colors,this->Scale); + break; + case VTK_CROSS_GLYPH: + this->CreateCross(pts,lines,polys,colors,this->Scale); + break; + case VTK_THICKCROSS_GLYPH: + this->CreateThickCross(pts,lines,polys,colors); + break; + case VTK_TRIANGLE_GLYPH: + this->CreateTriangle(pts,lines,polys,colors); + break; + case VTK_SQUARE_GLYPH: + this->CreateSquare(pts,lines,polys,colors); + break; + case VTK_CIRCLE_GLYPH: + this->CreateCircle(pts,lines,polys,colors); + break; + case VTK_DIAMOND_GLYPH: + this->CreateDiamond(pts,lines,polys,colors); + break; + case VTK_ARROW_GLYPH: + this->CreateArrow(pts,lines,polys,colors); + break; + case VTK_THICKARROW_GLYPH: + this->CreateThickArrow(pts,lines,polys,colors); + break; + case VTK_HOOKEDARROW_GLYPH: + this->CreateHookedArrow(pts,lines,polys,colors); + break; + case VTK_EDGEARROW_GLYPH: + this->CreateEdgeArrow(pts,lines,polys,colors); + break; + case VTK_SPECIFICARROW_GLYPH: + this->CreateSpecificArrow(pts,lines,polys,colors); + break; + } + + this->TransformGlyph(pts); + + //Clean up + output->SetPoints(pts); + pts->Delete(); + + output->SetVerts(verts); + verts->Delete(); + + output->SetLines(lines); + lines->Delete(); + + output->SetPolys(polys); + polys->Delete(); + + output->GetCellData()->SetScalars(colors); + colors->Delete(); + + return 1; +} + +void vvGlyphSource::CreateSpecificArrow(vtkPoints *pts, vtkCellArray *lines, + vtkCellArray *polys, vtkUnsignedCharArray *colors) +{ + //stem + vtkIdType ptIds[3]; + ptIds[0] = pts->InsertNextPoint( 0.0, 0.0, 0.0); + ptIds[1] = pts->InsertNextPoint( 1.0, 0.0, 0.0); + lines->InsertNextCell(2,ptIds); + colors->InsertNextValue(0); + colors->InsertNextValue(0); + colors->InsertNextValue(1); + + //arrow head + ptIds[0] = pts->InsertNextPoint( 0.7, -0.1, 0.0); + ptIds[1] = pts->InsertNextPoint( 1.0, 0.0, 0.0); + ptIds[2] = pts->InsertNextPoint( 0.7, 0.1, 0.0); + lines->InsertNextCell(3,ptIds); + colors->InsertNextValue(0); + colors->InsertNextValue(1); + colors->InsertNextValue(0); +} + +void vvGlyphSource::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} diff --git a/vv/vvGlyphSource.h b/vv/vvGlyphSource.h new file mode 100644 index 0000000..20b3e0a --- /dev/null +++ b/vv/vvGlyphSource.h @@ -0,0 +1,57 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvGlyphSource.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:58 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef __vvGlyphSource_h +#define __vvGlyphSource_h + +#include "vtkGlyphSource2D.h" + +#define VTK_SPECIFICARROW_GLYPH 13 + +class vvGlyphSource: public vtkGlyphSource2D +{ +public: + static vvGlyphSource *New(); + vtkTypeRevisionMacro(vvGlyphSource,vtkGlyphSource2D); + void PrintSelf(ostream& os, vtkIndent indent); + + void SetGlyphTypeToSpecificArrow() { + this->SetGlyphType(VTK_SPECIFICARROW_GLYPH); + } + + vtkSetClampMacro(GlyphType,int,VTK_NO_GLYPH,VTK_SPECIFICARROW_GLYPH); + +protected: + void CreateSpecificArrow(vtkPoints *pts, vtkCellArray *lines, + vtkCellArray *polys, vtkUnsignedCharArray *colors); + + int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); + +private: + + +}; +#endif diff --git a/vv/vvHelpDialog.h b/vv/vvHelpDialog.h new file mode 100644 index 0000000..2b51860 --- /dev/null +++ b/vv/vvHelpDialog.h @@ -0,0 +1,51 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvHelpDialog.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvHelpDialog_h +#define vvHelpDialog_h + +#include +#include + +#include "ui_vvHelpDialog.h" + +class vvHelpDialog : public QDialog, private Ui::vvHelpDialog +{ + Q_OBJECT + +public: + vvHelpDialog() { + setupUi(this); + } + ~vvHelpDialog() {} + +public slots: + +private: + +}; + +#endif diff --git a/vv/vvIcon.rc b/vv/vvIcon.rc new file mode 100755 index 0000000..f06ba51 --- /dev/null +++ b/vv/vvIcon.rc @@ -0,0 +1,4 @@ +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON "icons/ducky.ico" + diff --git a/vv/vvIcons.qrc b/vv/vvIcons.qrc new file mode 100644 index 0000000..f3ac659 --- /dev/null +++ b/vv/vvIcons.qrc @@ -0,0 +1,29 @@ + + + icons/crop.png + icons/splashscreen2.png + icons/splashscreen.PNG + icons/cut.png + icons/GPSup.png + icons/invertcolor.png + icons/cursor-uparrow.png + icons/cross.png + icons/undo.png + icons/filesave.png + icons/fileopen.png + icons/fusion.png + icons/open.png + icons/NOgrid.png + icons/NEgrid.png + icons/SOgrid.png + icons/SEgrid.png + icons/player_play.png + icons/player_pause.png + icons/ducky.png + icons/exit.png + icons/rotateright.png + icons/adjustsize.png + icons/standardbutton-apply-16.png + icons/standardbutton-cancel-16.png + + diff --git a/vv/vvImageMapToWLColors.cxx b/vv/vvImageMapToWLColors.cxx new file mode 100644 index 0000000..7a8f94c --- /dev/null +++ b/vv/vvImageMapToWLColors.cxx @@ -0,0 +1,325 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#include "vvImageMapToWLColors.h" +#include "clitkCommon.h" +#include "vtkDataArray.h" +#include "vtkImageData.h" +#include "vtkInformation.h" +#include "vtkInformationVector.h" +#include "vtkObjectFactory.h" +#include "vtkScalarsToColors.h" +#include "vtkPointData.h" +#include + +vtkStandardNewMacro(vvImageMapToWLColors); + +vvImageMapToWLColors::vvImageMapToWLColors() : + wl_mode(false) +{} + +template +void vtkImageMapToWindowLevelClamps ( vtkImageData *data, double w, + double l, T& lower, T& upper, + unsigned char &lower_val, + unsigned char &upper_val) +{ + double f_lower, f_upper, f_lower_val, f_upper_val; + double adjustedLower, adjustedUpper; + double range[2]; + + data->GetPointData()->GetScalars()->GetDataTypeRange( range ); + + f_lower = l - fabs(w) / 2.0; + f_upper = f_lower + fabs(w); + + // Set the correct lower value + if ( f_lower <= range[1]) + { + if (f_lower >= range[0]) + { + lower = static_cast(f_lower); + adjustedLower = f_lower; + } + else + { + lower = static_cast(range[0]); + adjustedLower = range[0]; + } + } + else + { + lower = static_cast(range[1]); + adjustedLower = range[1]; + } + + // Set the correct upper value + if ( f_upper >= range[0]) + { + if (f_upper <= range[1]) + { + upper = static_cast(f_upper); + adjustedUpper = f_upper; + } + else + { + upper = static_cast(range[1]); + adjustedUpper = range[1]; + } + } + else + { + upper = static_cast(range[0]); + adjustedUpper = range [0]; + } + + // now compute the lower and upper values + if (w >= 0) + { + f_lower_val = 255.0*(adjustedLower - f_lower)/w; + f_upper_val = 255.0*(adjustedUpper - f_lower)/w; + } + else + { + f_lower_val = 255.0 + 255.0*(adjustedLower - f_lower)/w; + f_upper_val = 255.0 + 255.0*(adjustedUpper - f_lower)/w; + } + + if (f_upper_val > 255) + { + upper_val = 255; + } + else if (f_upper_val < 0) + { + upper_val = 0; + } + else + { + upper_val = static_cast(f_upper_val); + } + + if (f_lower_val > 255) + { + lower_val = 255; + } + else if (f_lower_val < 0) + { + lower_val = 0; + } + else + { + lower_val = static_cast(f_lower_val); + } +} + +template +void vvImageMapToWindowLevelColorsExecute( + vtkImageMapToWindowLevelColors *self, + vtkImageData *inData, T *inPtr, + vtkImageData *outData, + unsigned char *outPtr, + int outExt[6], int id, bool wl_mode) +{ + int idxX, idxY, idxZ; + int extX, extY, extZ; + vtkIdType inIncX, inIncY, inIncZ; + vtkIdType outIncX, outIncY, outIncZ; + unsigned long count = 0; + unsigned long target; + int dataType = inData->GetScalarType(); + int numberOfComponents,numberOfOutputComponents,outputFormat; + int rowLength; + vtkScalarsToColors *lookupTable = self->GetLookupTable(); + unsigned char *outPtr1; + T *inPtr1; + unsigned char *optr; + T *iptr; + double shift = self->GetWindow() / 2.0 - self->GetLevel(); + double scale = 255.0 / self->GetWindow(); + + T lower, upper; + unsigned char lower_val, upper_val, result_val; + vtkImageMapToWindowLevelClamps( inData, self->GetWindow(), + self->GetLevel(), + lower, upper, lower_val, upper_val ); + + // find the region to loop over + extX = outExt[1] - outExt[0] + 1; + extY = outExt[3] - outExt[2] + 1; + extZ = outExt[5] - outExt[4] + 1; + + target = static_cast(extZ*extY/50.0); + target++; + + // Get increments to march through data + inData->GetContinuousIncrements(outExt, inIncX, inIncY, inIncZ); + + outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ); + numberOfComponents = inData->GetNumberOfScalarComponents(); + numberOfOutputComponents = outData->GetNumberOfScalarComponents(); + outputFormat = self->GetOutputFormat(); + + rowLength = extX*numberOfComponents; + + // Loop through output pixels + outPtr1 = outPtr; + inPtr1 = inPtr; + for (idxZ = 0; idxZ < extZ; idxZ++) + { + for (idxY = 0; !self->AbortExecute && idxY < extY; idxY++) + { + if (!id) + { + if (!(count%target)) + { + self->UpdateProgress(count/(50.0*target)); + } + count++; + } + + iptr = inPtr1; + optr = outPtr1; + + if ( lookupTable ) + { + lookupTable->MapScalarsThroughTable2( + inPtr1, + static_cast(outPtr1), + dataType,extX,numberOfComponents, + outputFormat); + if (wl_mode) + { + unsigned short ushort_val; + for (idxX = 0; idxX < extX; idxX++) + { + if (*iptr <= lower) + { + ushort_val = lower_val; + } + else if (*iptr >= upper) + { + ushort_val = upper_val; + } + else + { + ushort_val = static_cast((*iptr + shift)*scale); + } + *optr = static_cast((*optr * ushort_val) >> 8); + switch (outputFormat) + { + case VTK_RGBA: + *(optr+1) = static_cast( + (*(optr+1) * ushort_val) >> 8); + *(optr+2) = static_cast( + (*(optr+2) * ushort_val) >> 8); + *(optr+3) = 255; + break; + case VTK_RGB: + *(optr+1) = static_cast( + (*(optr+1) * ushort_val) >> 8); + *(optr+2) = static_cast( + (*(optr+2) * ushort_val) >> 8); + break; + case VTK_LUMINANCE_ALPHA: + *(optr+1) = 255; + break; + } + iptr += numberOfComponents; + optr += numberOfOutputComponents; + } + } + } + else + { + for (idxX = 0; idxX < extX; idxX++) + { + if (*iptr <= lower) + { + result_val = lower_val; + } + else if (*iptr >= upper) + { + result_val = upper_val; + } + else + { + result_val = static_cast((*iptr + shift)*scale); + } + *optr = result_val; + switch (outputFormat) + { + case VTK_RGBA: + *(optr+1) = result_val; + *(optr+2) = result_val; + *(optr+3) = 255; + break; + case VTK_RGB: + *(optr+1) = result_val; + *(optr+2) = result_val; + break; + case VTK_LUMINANCE_ALPHA: + *(optr+1) = 255; + break; + } + iptr += numberOfComponents; + optr += numberOfOutputComponents; + } + } + outPtr1 += outIncY + extX*numberOfOutputComponents; + inPtr1 += inIncY + rowLength; + } + outPtr1 += outIncZ; + inPtr1 += inIncZ; + } +} + + +void vvImageMapToWLColors::ThreadedRequestData( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **vtkNotUsed(inputVector), + vtkInformationVector *vtkNotUsed(outputVector), + vtkImageData ***inData, + vtkImageData **outData, + int outExt[6], int id) +{ + void *inPtr = inData[0][0]->GetScalarPointerForExtent(outExt); + void *outPtr = outData[0]->GetScalarPointerForExtent(outExt); + + switch (inData[0][0]->GetScalarType()) + { + vtkTemplateMacro( + vvImageMapToWindowLevelColorsExecute(this, + inData[0][0], + static_cast(inPtr), + outData[0], + static_cast(outPtr), + outExt, + id,wl_mode)); + default: + vtkErrorMacro(<< "Execute: Unknown ScalarType"); + return; + } +} + + diff --git a/vv/vvImageMapToWLColors.h b/vv/vvImageMapToWLColors.h new file mode 100644 index 0000000..ca6cd73 --- /dev/null +++ b/vv/vvImageMapToWLColors.h @@ -0,0 +1,50 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + Program: vv + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvImageMapToWLColors_h +#define vvImageMapToWLColors_h + +#include + +//This is mostly a copy of the vtk parent class, but with the option +//not to use the W/L when a LUT is set + +class vvImageMapToWLColors : public vtkImageMapToWindowLevelColors +{ +public: + static vvImageMapToWLColors * New(); + vvImageMapToWLColors(); + void SetWindowLevelMode(bool wl) {wl_mode=wl;} + void ThreadedRequestData(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector, + vtkImageData ***inData, vtkImageData **outData, + int extent[6], int id); + +protected: + bool wl_mode; + +}; + +#endif diff --git a/vv/vvImageReader.cxx b/vv/vvImageReader.cxx new file mode 100644 index 0000000..7e4a4e2 --- /dev/null +++ b/vv/vvImageReader.cxx @@ -0,0 +1,114 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvImageReader.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvImageReader_CXX +#define vvImageReader_CXX + +#include +#include +#include "vvImageReader.h" +#include "vvImageReader.txx" + + +//==================================================================== +vvImageReader::vvImageReader() +{ + mImage = NULL; + mInputFilenames.resize(0); + mLastError = ""; + mType = UNDEFINEDIMAGETYPE; +} + +vvImageReader::~vvImageReader() { } + +void vvImageReader::Update(LoadedImageType type) +{ + itk::ImageIOBase::Pointer reader = itk::ImageIOFactory::CreateImageIO(mInputFilenames[0].c_str(), itk::ImageIOFactory::ReadMode); + if (!reader) { + mLastError="Unable to read file."; + } + else { + reader->SetFileName(mInputFilenames[0]); + reader->ReadImageInformation(); + if (mInputFilenames.size() > 1) + Update(reader->GetNumberOfDimensions()+1,reader->GetComponentTypeAsString(reader->GetComponentType()),type); + else + Update(reader->GetNumberOfDimensions(),reader->GetComponentTypeAsString(reader->GetComponentType()),type); + } +} + +//==================================================================== +void vvImageReader::Update(int dim,std::string inputPixelType, LoadedImageType type) { + //CALL_FOR_ALL_DIMS(dim,UpdateWithDim,inputPixelType); + mType = type; + mDim = dim; + mInputPixelType=inputPixelType; + this->start(); //Start heavy read operation in a separate thread + while (this->isRunning()) + { + qApp->processEvents(); + this->wait(50); + } +} + +void vvImageReader::run() +{ + switch(mDim) + { + case 2: + UpdateWithDim<2>(mInputPixelType); + break;; + case 3: + UpdateWithDim<3>(mInputPixelType); + break;; + case 4: + UpdateWithDim<4>(mInputPixelType); + break;; + default: + std::cerr << "dimension unknown in Update ! " << std::endl; + } +} +//==================================================================== + +//==================================================================== +/*void vvImageReader::Extract(int dim, std::string inputPixelType, int slice) { + CALL_FOR_ALL_DIMS(dim, ExtractWithDim, inputPixelType, slice); +}*/ +//==================================================================== +void vvImageReader::SetInputFilename(const std::string & filename) +{ + mInputFilenames.resize(0); + mInputFilenames.push_back(filename); +} + +//==================================================================== +void vvImageReader::SetInputFilenames(const std::vector & filenames) { + mInputFilenames = filenames; +} +//==================================================================== + +#endif + diff --git a/vv/vvImageReader.h b/vv/vvImageReader.h new file mode 100644 index 0000000..c9005aa --- /dev/null +++ b/vv/vvImageReader.h @@ -0,0 +1,92 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvImageReader.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvImageReader_H +#define vvImageReader_H + +#include +#include +#include + +#include "itkCommand.h" +#include "vvImage.h" +#include "vvConstants.h" + +class vvImageReader : public QThread { + +public: + vvImageReader(); + ~vvImageReader(); + + void SetInputFilename(const std::string & filename); + void SetInputFilenames(const std::vector & filenames); + + vvImage::Pointer GetOutput() { + return mImage; + } + + std::string GetLastError() { + return mLastError; + } + + //==================================================================== + // Main function + void Update(LoadedImageType type); + void Update(int dim, std::string InputPixelType, LoadedImageType type); + //void Extract(int dim, std::string InputPixelType, int slice); + +protected: + void run(); + //==================================================================== + std::vector mInputFilenames; + ///Method used to load the image, see vvConstants.h for definition + LoadedImageType mType; + itk::Command::Pointer mObserver; + + std::string mLastError; + + //==================================================================== + template + void UpdateWithDim(std::string inputPixelType); + + //==================================================================== + /*template + void ExtractWithDim(std::string inputPixelType, int slice);*/ + + //==================================================================== + template + void UpdateWithDimAndInputPixelType(); + ///Input dimension and pixel type + int mDim; + std::string mInputPixelType; + +private: + vvImage::Pointer mImage; + +}; // end class vvImageReader + +#endif /* end #define CLITKvvImageReader_H */ + diff --git a/vv/vvImageReader.txx b/vv/vvImageReader.txx new file mode 100644 index 0000000..cdddf06 --- /dev/null +++ b/vv/vvImageReader.txx @@ -0,0 +1,163 @@ +/*========================================================================= + +Program: vv +Module: $RCSfile: vvImageReader.txx,v $ +Language: C++ +Date: $Date: 2010/01/06 13:31:57 $ +Version: $Revision: 1.1 $ +Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvImageReader_TXX +#define vvImageReader_TXX +#include + +#include +#include + +#include "clitkCommon.h" +#include "itkImageToVTKImageFilter.h" +#include "vvFromITK.h" +#include "vvConstants.h" + +template +void vvImageReader::UpdateWithDim(std::string InputPixelType) +{ + if (mType == VECTORFIELD) + UpdateWithDimAndInputPixelType,VImageDimension>(); + else if (InputPixelType == "short") + UpdateWithDimAndInputPixelType(); + else if (InputPixelType == "unsigned_short") + UpdateWithDimAndInputPixelType(); + else if (InputPixelType == "char") + UpdateWithDimAndInputPixelType(); + else if (InputPixelType == "unsigned_char") + UpdateWithDimAndInputPixelType(); + else if (InputPixelType == "int") + UpdateWithDimAndInputPixelType(); + else if (InputPixelType == "double") + UpdateWithDimAndInputPixelType(); + else if (InputPixelType == "float") + UpdateWithDimAndInputPixelType(); + else + std::cerr << "Error, input pixel type : " << InputPixelType << " unknown !" << std::endl; +} +//==================================================================== + +template +void vvImageReader::UpdateWithDimAndInputPixelType() +{ + if (mType == MERGEDWITHTIME) // In this case we can load the images + // one at the time to avoid excessive + // memory use + { + typedef itk::Image< InputPixelType, VImageDimension-1 > InputImageType; + typedef itk::ImageFileReader ReaderType; + typename ReaderType::Pointer reader = ReaderType::New(); + typedef itk::ImageToVTKImageFilter ConnectorType; + typename ConnectorType::Pointer connector = ConnectorType::New(); + connector->SetInput(reader->GetOutput()); + mImage=vvImage::New(); + for (std::vector::const_iterator i=mInputFilenames.begin();i!=mInputFilenames.end();i++) + { + std::cout << (*i) << std::endl; + reader->SetFileName(*i); + try { + reader->Update(); + } + catch ( itk::ExceptionObject & err ) { + std::cerr << "Error while reading " << mInputFilenames[0].c_str() + << " " << err << std::endl; + std::stringstream error; + error << err; + mLastError = error.str(); + return; + } + try { + connector->Update(); + } + catch ( itk::ExceptionObject & err ) { + std::cerr << "Error while setting vvImage from ITK (MERGEDWITHTIME)" + << " " << err << std::endl; + } + vtkImageData *image = vtkImageData::New(); + image->DeepCopy(connector->GetOutput()); + mImage->AddImage(image); + } + } + else + { + if (mInputFilenames.size() > 1) + { + typedef itk::Image< InputPixelType, VImageDimension > InputImageType; + typedef itk::ImageSeriesReader ReaderType; + typename ReaderType::Pointer reader = ReaderType::New(); + for (std::vector::const_iterator i=mInputFilenames.begin();i!=mInputFilenames.end();i++) + std::cout << (*i) << std::endl; + reader->SetFileNames(mInputFilenames); + //if (mUseAnObserver) { + //reader->AddObserver(itk::ProgressEvent(), mObserver); + //} + try { + reader->Update(); + } + catch ( itk::ExceptionObject & err ) { + std::cerr << "Error while reading image series:" << err << std::endl; + std::stringstream error; + error << err; + mLastError = error.str(); + return; + } + if (mType == IMAGEWITHTIME) + mImage=vvImageFromITK(reader->GetOutput(),true); + else + mImage=vvImageFromITK(reader->GetOutput()); + } + else + { + typedef itk::Image< InputPixelType, VImageDimension > InputImageType; + typedef itk::ImageFileReader ReaderType; + typename ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(mInputFilenames[0]); + //if (mUseAnObserver) { + //reader->AddObserver(itk::ProgressEvent(), mObserver); + //} + try { + reader->Update(); + } + catch ( itk::ExceptionObject & err ) { + std::cerr << "Error while reading " << mInputFilenames[0].c_str() + << " " << err << std::endl; + std::stringstream error; + error << err; + mLastError = error.str(); + return; + } + if (mType == IMAGEWITHTIME) + mImage=vvImageFromITK(reader->GetOutput(),true); + else + mImage=vvImageFromITK(reader->GetOutput()); + } + } +} +//==================================================================== + + +#endif /* end #define vvImageReader_TXX */ + diff --git a/vv/vvImageWarp.cxx b/vv/vvImageWarp.cxx new file mode 100644 index 0000000..99781b9 --- /dev/null +++ b/vv/vvImageWarp.cxx @@ -0,0 +1,159 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include "vvToITK.h" +#include "vvFromITK.h" + +#include "vvImageWarp.h" +#include "clitkCommon.h" + +//==================================================================== +vvImageWarp::vvImageWarp(vvImage::Pointer input,vvImage::Pointer vf,unsigned int ref_image,QWidget* parent): + mRefImage(ref_image), + parent_window(parent), + mInputImage(input), + mVF(vf) +{} + + +//==================================================================== +template +void vvImageWarp::Update_WithDim() { +#define TRY_TYPE(TYPE) \ + if (clitk::IsSameType(mInputImage->GetScalarTypeAsString())) { this->Update_WithDimAndPixelType(); return; } +// TRY_TYPE(signed char); +// TRY_TYPE(uchar); + TRY_TYPE(short); +// TRY_TYPE(ushort); +// TRY_TYPE(int); // no uint ... +// TRY_TYPE(float); + //TRY_TYPE(double); +#undef TRY_TYPE + + std::string list = clitk::CreateListOfTypes(); + std::cerr << "Error, I don't know the type '" << mInputImage->GetScalarTypeAsString() << "' for the input image. " + << std::endl << "Known types are " << list << std::endl; + exit(0); +} + +//==================================================================== +template +void vvImageWarp::Update_WithDimAndPixelType() { + QProgressDialog progress(parent_window); + progress.setCancelButton(0); + progress.setLabelText("Computing warped and ventilation images..."); + progress.show(); + typedef itk::Image ImageType; + typedef itk::Image JacobianImageType; + typedef itk::Image,Dim> VectorImageType; + typedef std::vector ImageSeriesType; + ImageSeriesType input = vvImageToITKImageVector(mInputImage); + ImageSeriesType output; + + typename itk::VTKImageToImageFilter::Pointer vf_connector= + itk::VTKImageToImageFilter::New(); + + //Warp, then join, then convert to vv + typedef itk::WarpImageFilter WarpFilterType; + typedef itk::DisplacementFieldJacobianDeterminantFilter JacobianFilterType; + vvImage::Pointer result=vvImage::New(); + typedef itk::JoinSeriesImageFilter< ImageType,itk::Image > JoinFilterType; + typedef itk::JoinSeriesImageFilter< JacobianImageType,itk::Image > JacobianJoinFilterType; + typename JoinFilterType::Pointer join=JoinFilterType::New(); + typename JoinFilterType::Pointer diff_join=JoinFilterType::New(); + typename JacobianJoinFilterType::Pointer jacobian_join=JacobianJoinFilterType::New(); + join->SetSpacing(1); + join->SetOrigin(0); //Set the temporal origin + diff_join->SetSpacing(1); + diff_join->SetOrigin(0); + jacobian_join->SetSpacing(1); + jacobian_join->SetOrigin(0); + typedef itk::SubtractImageFilter DiffFilter; + std::vector warped_images; + + for (unsigned int num = 0; num < input.size(); num++) + { + typename WarpFilterType::Pointer warp_filter=WarpFilterType::New(); + typename JacobianFilterType::Pointer jacobian_filter=JacobianFilterType::New(); + jacobian_filter->SetUseImageSpacingOn(); + vf_connector->SetInput(mVF->GetVTKImages()[num]); + warp_filter->SetInput(input[num]); + warp_filter->SetDeformationField(vf_connector->GetOutput()); + jacobian_filter->SetInput(vf_connector->GetOutput()); + warp_filter->SetOutputSpacing(input[num]->GetSpacing()); + warp_filter->SetOutputOrigin(input[num]->GetOrigin()); + warp_filter->SetEdgePaddingValue(-1000); + warp_filter->Update(); + jacobian_filter->Update(); + warped_images.push_back(warp_filter->GetOutput()); + jacobian_join->PushBackInput(jacobian_filter->GetOutput()); + join->PushBackInput(warp_filter->GetOutput()); + progress.setValue(progress.value()+1); + } + for (typename std::vector::const_iterator i = warped_images.begin(); i!=warped_images.end();i++) + { + typename DiffFilter::Pointer diff_filter = DiffFilter::New(); + diff_filter->SetInput2(*i); + diff_filter->SetInput1(*(warped_images.begin()+mRefImage)); + diff_filter->Update(); + diff_join->PushBackInput(diff_filter->GetOutput()); + progress.setValue(progress.value()+1); + } + join->Update(); + diff_join->Update(); + jacobian_join->Update(); + mWarpedImage = vvImageFromITK(join->GetOutput()); + mDiffImage = vvImageFromITK(diff_join->GetOutput()); + mJacobianImage = vvImageFromITK(jacobian_join->GetOutput()); + //mJacobianImage = vvImageFromITK(temporal_filter->GetOutput()); +} +//==================================================================== +// + +bool vvImageWarp::ComputeWarpedImage() +{ + for (int i=0;iGetNumberOfDimensions();i++) + { + if (mInputImage->GetSpacing()[i] != mVF->GetSpacing()[i]) + return false; + } + switch (mInputImage->GetNumberOfDimensions()) + { +// case 2: this->Update_WithDim<2>(); break;; +// case 3: this->Update_WithDim<3>(); break;; + case 4: + this->Update_WithDim<3>(); + break;; + default: + DD("Error: dimension not handled."); + } + return true; +} diff --git a/vv/vvImageWarp.h b/vv/vvImageWarp.h new file mode 100644 index 0000000..c9e2085 --- /dev/null +++ b/vv/vvImageWarp.h @@ -0,0 +1,61 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + Program: vv + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvImageWarp_h +#define vvImageWarp_h + +#include "vvImage.h" +class QWidget; + +/// Allows the computation of a warped image sequence and a difference image sequence, for the purpose of verifying registration results +class vvImageWarp +{ +public: + ///Slicer manager containing the image sequence and deformation field, plus the index of the image used as a reference for the registration + vvImageWarp(vvImage::Pointer input,vvImage::Pointer vf,unsigned int ref_image,QWidget* parent); + ///Computes a warped sequence and a difference image sequence. Return false in case of error + bool ComputeWarpedImage(); + vvImage::Pointer GetWarpedImage() { + return mWarpedImage; + } + vvImage::Pointer GetDiffImage() { + return mDiffImage; + } + vvImage::Pointer GetJacobianImage() { + return mJacobianImage; + } + +protected: + template void Update_WithDimAndPixelType(); + template void Update_WithDim(); + unsigned int mRefImage; + vvImage::Pointer mWarpedImage; + vvImage::Pointer mDiffImage; + vvImage::Pointer mJacobianImage; + QWidget * parent_window; + vvImage::Pointer mInputImage; + vvImage::Pointer mVF; +}; + +#endif diff --git a/vv/vvImageWriter.cxx b/vv/vvImageWriter.cxx new file mode 100644 index 0000000..7de97e3 --- /dev/null +++ b/vv/vvImageWriter.cxx @@ -0,0 +1,69 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvImageWriter.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvImageWriter_CXX +#define vvImageWriter_CXX + +#include "vvImageWriter.h" +#include "vvImageWriter.txx" + +#include +//==================================================================== +vvImageWriter::vvImageWriter() { + mImage = NULL; + mOutputFilename = ""; + mLastError = ""; + mUseAnObserver = false; +} +//==================================================================== + +//==================================================================== +vvImageWriter::~vvImageWriter() { +} +//==================================================================== + +//==================================================================== +void vvImageWriter::Update(int dim,std::string OutputPixelType) { + //CALL_FOR_ALL_DIMS(dim,UpdateWithDim,inputPixelType); + if (dim == 2) + UpdateWithDim<2>(OutputPixelType); + else if (dim == 3) + UpdateWithDim<3>(OutputPixelType); + else if (dim == 4) + UpdateWithDim<4>(OutputPixelType); + else + std::cerr << "dim not know in Update ! " << std::endl; +} +//==================================================================== + +//==================================================================== +void vvImageWriter::SetOutputFileName(std::string filename) { + mOutputFilename = filename; +} +//==================================================================== + +#endif + diff --git a/vv/vvImageWriter.h b/vv/vvImageWriter.h new file mode 100644 index 0000000..6ead3d8 --- /dev/null +++ b/vv/vvImageWriter.h @@ -0,0 +1,89 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvImageWriter.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:58 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvImageWriter_H +#define vvImageWriter_H + +#include + +// ITK includes +#include "itkImage.h" +#include "itkCommand.h" +#include "vvImage.h" + +class vvImageWriter { + +public: + // constructor + vvImageWriter(); + ~vvImageWriter(); + + void SetOutputFileName(std::string filename); + void SetObserver(itk::Command::Pointer o) { + mUseAnObserver = true; + mObserver = o; + } + void DisableObserver() { + mUseAnObserver = false; + } + + void SetInput(vvImage::Pointer image) { + mImage = image; + } + + std::string GetLastError() { + return mLastError; + } + + //==================================================================== + // Main function + void Update() { + Update(mImage->GetNumberOfDimensions(),mImage->GetScalarTypeAsString()); + } + void Update(int dim, std::string OutputPixelType); + +protected: + //==================================================================== + std::string mOutputFilename; + itk::Command::Pointer mObserver; + + std::string mLastError; + bool mUseAnObserver; + + //==================================================================== + template + void UpdateWithDim(std::string OutputPixelType); + + //==================================================================== + template + void UpdateWithDimAndOutputPixelType(); + +private: + vvImage::Pointer mImage; + +}; // end class vvImageWriter + +#endif /* end #define vvImageWriter_H */ diff --git a/vv/vvImageWriter.txx b/vv/vvImageWriter.txx new file mode 100644 index 0000000..8d9187c --- /dev/null +++ b/vv/vvImageWriter.txx @@ -0,0 +1,100 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvImageWriter.txx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvImageWriter_TXX +#define vvImageWriter_TXX + +#include +#include "vvToITK.h" + +//==================================================================== +template +void vvImageWriter::UpdateWithDim(std::string OutputPixelType) +{ + if (OutputPixelType == "short") + { + UpdateWithDimAndOutputPixelType(); + } + else if (OutputPixelType == "unsigned_short") + { + UpdateWithDimAndOutputPixelType(); + } + else if (OutputPixelType == "char") + { + UpdateWithDimAndOutputPixelType(); + } + else if (OutputPixelType == "unsigned_char") + { + UpdateWithDimAndOutputPixelType(); + } + else if (OutputPixelType == "int") + { + UpdateWithDimAndOutputPixelType(); + } + else if (OutputPixelType == "double") + { + UpdateWithDimAndOutputPixelType(); + } + else if (OutputPixelType == "float") + { + UpdateWithDimAndOutputPixelType(); + } + else + { + std::cerr << "Error, output pixel type : \"" << OutputPixelType << "\" unknown !" << std::endl; + } +} +//==================================================================== + +//==================================================================== +template +void vvImageWriter::UpdateWithDimAndOutputPixelType() +{ + //Create the writer + typedef itk::Image< OutputPixelType, VImageDimension > OutputImageType; + typedef itk::ImageFileWriter WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(mOutputFilename); + writer->SetInput(vvImageToITK(mImage)); + if (mUseAnObserver) { + writer->AddObserver(itk::ProgressEvent(), mObserver); + } + try { + writer->Update(); + } + catch ( itk::ExceptionObject & err ) { + std::cerr << "Error while reading " << mOutputFilename.c_str() + << " " << err << std::endl; + std::stringstream error; + error << err; + mLastError = error.str(); + return; + } +} +//==================================================================== + +#endif /* end #define vvImageWriter_TXX */ + diff --git a/vv/vvInfoPanel.cxx b/vv/vvInfoPanel.cxx new file mode 100644 index 0000000..0cf41e3 --- /dev/null +++ b/vv/vvInfoPanel.cxx @@ -0,0 +1,149 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvInfoPanel.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#include +#include + +#include "vvInfoPanel.h" + +void vvInfoPanel::setFileName(QString text) +{ + if (text.size() > 30) + imageLabel->setText("..." + text.right(27)); + else + imageLabel->setText(text); +} + +void vvInfoPanel::setDimension(QString text) +{ + dimensionLabel->setText(text); +} + +void vvInfoPanel::setSizeMM(QString text) +{ + sizeMMLabel->setText(text); +} + +void vvInfoPanel::setNPixel(QString text) +{ + nPixelLabel->setText(text); +} + +void vvInfoPanel::setSizePixel(QString text) +{ + sizePixelLabel->setText(text); +} + +void vvInfoPanel::setOrigin(QString text) +{ + originLabel->setText(text); +} + +void vvInfoPanel::setSpacing(QString text) +{ + spacingLabel->setText(text); +} + +void vvInfoPanel::setCurrentInfo(int visibility, double x, double y, double z, double X, double Y, double Z, double value) +{ + QString world = ""; + QString mouse = ""; + QString val = ""; + if (visibility) + { + world += QString::number(x,'f',1) + " "; + world += QString::number(y,'f',1) + " "; + world += QString::number(z,'f',1) + " "; + + mouse += QString::number(X,'f',1) + " "; + mouse += QString::number(Y,'f',1) + " "; + mouse += QString::number(Z,'f',1) + " "; + + val += QString::number(value); + } + worldPosLabel->setText(world); + pixelPosLabel->setText(mouse); + valueLabel->setText(val); +} + + +void vvInfoPanel::setViews(int window, int view, int slice) +{ + QString viewString; + switch (view) + { + case 0: + { + viewString = "Sagital, "; + break; + } + case 1: + { + viewString = "Coronal, "; + break; + } + case 2: + { + viewString = "Axial, "; + break; + } + } + + QString text = viewString; + if (view != -1) + { + text += "current slice : "; + text += QString::number(slice); + } + else + { + text = "Disable"; + } + + switch (window) + { + case 0: + { + ULLabel->setText(text); + break; + } + case 1: + { + URLabel->setText(text); + break; + } + case 2: + { + DLLabel->setText(text); + break; + } + case 3: + { + DRLabel->setText(text); + break; + } + } +} diff --git a/vv/vvInfoPanel.h b/vv/vvInfoPanel.h new file mode 100644 index 0000000..abefc75 --- /dev/null +++ b/vv/vvInfoPanel.h @@ -0,0 +1,61 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvInfoPanel.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvInfoPanel_h +#define vvInfoPanel_h + +#include +#include + +#include "ui_vvInfoPanel.h" + +class vvInfoPanel : public QWidget, private Ui::vvInfoPanel +{ + Q_OBJECT + +public: + vvInfoPanel(QWidget * parent=0):QWidget(parent) { + setupUi(this); + } + ~vvInfoPanel() {} + + void setFileName(QString text); + void setSizeMM(QString text); + void setOrigin(QString text); + void setSpacing(QString text); + void setNPixel(QString text); + void setDimension(QString text); + void setSizePixel(QString text); + void setCurrentInfo(int visibility, double x, double y, double z, double X, double Y, double Z, double value); + void setViews(int window, int view, int slice); + +public slots: + +private: + +}; + +#endif diff --git a/vv/vvInit.cxx b/vv/vvInit.cxx new file mode 100644 index 0000000..8bfe258 --- /dev/null +++ b/vv/vvInit.cxx @@ -0,0 +1,46 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvInit.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:58 $ + Version: $Revision: 1.1 $ + Author : Joël Schaerer (joel.schaerer@insa-lyon.fr) + + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#include "nkitkXDRImageIO.h" +#include "nkitkXDRImageIOFactory.h" +#include "clitkVoxImageIO.h" +#include "clitkVoxImageIOFactory.h" +#include "clitkVfImageIO.h" +#include "clitkVfImageIOFactory.h" + +#include "itkImage.h" +#include "itkImageFileReader.h" +#include "itkByteSwapper.h" + + +void initialize_IO() +{ + itk::ImageIOFactory::RegisterBuiltInFactories(); + clitk::VoxImageIOFactory::RegisterOneFactory(); + clitk::VfImageIOFactory::RegisterOneFactory(); + nkitk::XDRImageIOFactory::RegisterOneFactory(); +} diff --git a/vv/vvInit.h b/vv/vvInit.h new file mode 100644 index 0000000..c8c2f93 --- /dev/null +++ b/vv/vvInit.h @@ -0,0 +1,35 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvInit.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Joël Schaerer (joel.schaerer@insa-lyon.fr) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#ifndef vvInit_h +#define vvInit_h +//This file is for stuff that must be done to initialize vv, to avoid bloating the main vv.cxx with boilerplate code + +// Initialize the factories needed for IO +void initialize_IO(); + +#endif diff --git a/vv/vvInteractorStyleNavigator.cxx b/vv/vvInteractorStyleNavigator.cxx new file mode 100644 index 0000000..281067e --- /dev/null +++ b/vv/vvInteractorStyleNavigator.cxx @@ -0,0 +1,623 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvInteractorStyleNavigator.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#include "vvInteractorStyleNavigator.h" + +#include "vtkAbstractPropPicker.h" +#include "vtkAssemblyPath.h" +#include "vtkCallbackCommand.h" +#include "vtkMath.h" +#include "vtkObjectFactory.h" +#include "vtkCamera.h" +#include "vtkRenderWindow.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkRenderer.h" +#include +#include "clitkCommon.h" + + +vtkCxxRevisionMacro(vvInteractorStyleNavigator, "$Revision: 1.1 $"); +vtkStandardNewMacro(vvInteractorStyleNavigator); + +//---------------------------------------------------------------------------- +vvInteractorStyleNavigator::vvInteractorStyleNavigator() +{ + this->WindowLevelStartPosition[0] = 0; + this->WindowLevelStartPosition[1] = 0; + + this->WindowLevelCurrentPosition[0] = 0; + this->WindowLevelCurrentPosition[1] = 0; + + this->MotionFactor = 10.0; +} + +//---------------------------------------------------------------------------- +vvInteractorStyleNavigator::~vvInteractorStyleNavigator() +{ + CurrentRenderer=NULL; +} + +void vvInteractorStyleNavigator::FindPokedRenderer(int dummy1,int dummy2) +{ + vtkRenderWindow * renwin=this->GetInteractor()->GetRenderWindow(); + renwin->GetRenderers()->InitTraversal(); + while (true) + { + vtkRenderer* current = renwin->GetRenderers()->GetNextItem(); + if (current==NULL || current->GetDraw()) + { + CurrentRenderer=current; + return; + } + } +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::StartWindowLevel() +{ + if (this->State != VTKIS_NONE) + { + return; + } + this->StartState(VTKIS_WINDOW_LEVEL); + this->InvokeEvent(vtkCommand::StartWindowLevelEvent,this); +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::EndWindowLevel() +{ + if (this->State != VTKIS_WINDOW_LEVEL) + { + return; + } + this->InvokeEvent(vtkCommand::EndWindowLevelEvent, this); + this->StopState(); +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::StartPick() +{ + if (this->State != VTKIS_NONE) + { + return; + } + this->StartState(VTKIS_PICK); + this->InvokeEvent(vtkCommand::StartPickEvent, this); +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::EndPick() +{ + if (this->State != VTKIS_PICK) + { + return; + } + this->InvokeEvent(vtkCommand::EndPickEvent, this); + this->StopState(); +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::OnMouseMove() +{ + int x = this->Interactor->GetEventPosition()[0]; + int y = this->Interactor->GetEventPosition()[1]; + + switch (this->State) + { + case VTKIS_WINDOW_LEVEL: + this->FindPokedRenderer(x, y); + this->WindowLevel(); + this->InvokeEvent(vtkCommand::InteractionEvent, NULL); + break; + + case VTKIS_PICK: + this->FindPokedRenderer(x, y); + this->Pick(); + this->InvokeEvent(vtkCommand::InteractionEvent, NULL); + break; + + case VTKIS_PAN: + this->FindPokedRenderer(x, y); + this->Pan(); + this->InvokeEvent(vtkCommand::InteractionEvent, NULL); + break; + + case VTKIS_DOLLY: + this->FindPokedRenderer(x, y); + this->Dolly(); + this->InvokeEvent(vtkCommand::InteractionEvent, NULL); + break; + + default: + this->InvokeEvent(vtkCommand::UserEvent, NULL); + break; + } + + // Call parent to handle all other states and perform additional work + +} + +void vvInteractorStyleNavigator::OnEnter() +{ + // int x = this->Interactor->GetEventPosition()[0]; + //int y = this->Interactor->GetEventPosition()[1]; + + switch (this->State) + { + case VTKIS_WINDOW_LEVEL: + break; + + case VTKIS_PICK: + break; + + case VTKIS_PAN: + break; + + default: + this->InvokeEvent(vtkCommand::EnterEvent, NULL); + break; + } + + // Call parent to handle all other states and perform additional work + +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::OnLeave() +{ + // int x = this->Interactor->GetEventPosition()[0]; + //int y = this->Interactor->GetEventPosition()[1]; + + switch (this->State) + { + case VTKIS_WINDOW_LEVEL: + break; + + case VTKIS_PICK: + break; + + case VTKIS_PAN: + break; + + default: + this->InvokeEvent(vtkCommand::LeaveEvent, NULL); + break; + } + + // Call parent to handle all other states and perform additional work + +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::OnRightButtonDown() +{ + int x = this->Interactor->GetEventPosition()[0]; + int y = this->Interactor->GetEventPosition()[1]; + + this->FindPokedRenderer(x, y); + if (this->CurrentRenderer == NULL) + { + return; + } + + // Redefine this button to handle window/level + this->GrabFocus(this->EventCallbackCommand); + if (!this->Interactor->GetShiftKey() && !this->Interactor->GetControlKey()) + { + this->WindowLevelStartPosition[0] = x; + this->WindowLevelStartPosition[1] = y; + this->StartWindowLevel(); + } + + // The rest of the button + key combinations remain the same + + else + { + this->Superclass::OnRightButtonDown(); + } +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::OnRightButtonUp() +{ + switch (this->State) + { + case VTKIS_WINDOW_LEVEL: + this->EndWindowLevel(); + if ( this->Interactor ) + { + this->ReleaseFocus(); + } + break; + } + + // Call parent to handle all other states and perform additional work + + this->Superclass::OnRightButtonUp(); +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::OnLeftButtonDown() +{ + int x = this->Interactor->GetEventPosition()[0]; + int y = this->Interactor->GetEventPosition()[1]; + + this->FindPokedRenderer(x, y); + if (this->CurrentRenderer == NULL) + { + return; + } + + // Redefine this button to handle pick + this->GrabFocus(this->EventCallbackCommand); + if (!this->Interactor->GetShiftKey() && !this->Interactor->GetControlKey()) + { + this->StartPick(); + } + + // The rest of the button + key combinations remain the same + + else + { + this->Superclass::OnLeftButtonDown(); + } +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::OnLeftButtonUp() +{ + switch (this->State) + { + case VTKIS_PICK: + this->EndPick(); + if ( this->Interactor ) + { + this->ReleaseFocus(); + } + break; + } + + // Call parent to handle all other states and perform additional work + + this->Superclass::OnLeftButtonUp(); +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::OnMiddleButtonDown() +{ + this->FindPokedRenderer(this->Interactor->GetEventPosition()[0], + this->Interactor->GetEventPosition()[1]); + if (this->CurrentRenderer == NULL) + { + return; + } + this->CurrentRenderer->GetRenderWindow()->SetCurrentCursor(8); + this->GrabFocus(this->EventCallbackCommand); + this->StartPan(); +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::OnMiddleButtonUp() +{ + switch (this->State) + { + case VTKIS_PAN: + this->EndPan(); + if ( this->Interactor ) + { + this->Interactor->GetRenderWindow()->SetCurrentCursor(0); + this->ReleaseFocus(); + } + break; + } +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::OnChar() +{ + vtkRenderWindowInteractor *rwi = this->Interactor; + + switch (rwi->GetKeyCode()) + { + case 'f' : + case 'F' : + { + this->AnimState = VTKIS_ANIM_ON; + this->AnimState = VTKIS_ANIM_OFF; + break; + } + + case 'w' : + case 'W' : + { + this->FindPokedRenderer(this->Interactor->GetEventPosition()[0], + this->Interactor->GetEventPosition()[1]); + if (this->CurrentRenderer == NULL) + { + return; + } + this->GrabFocus(this->EventCallbackCommand); + this->StartDolly(); + double factor = -2; + this->Dolly(pow((double)1.1, factor)); + this->EndDolly(); + this->ReleaseFocus(); + break; + } + case 'x' : + case 'X' : + { + this->FindPokedRenderer(rwi->GetEventPosition()[0], + rwi->GetEventPosition()[1]); + if (this->CurrentRenderer == NULL) + { + return; + } + this->GrabFocus(this->EventCallbackCommand); + this->StartDolly(); + double factor = 2; + this->Dolly(pow((double)1.1, factor)); + this->EndDolly(); + this->ReleaseFocus(); + break; + } + case '3' : + // Disable StereoVision + break; + case 'r' : + case 'R' : + //Do nothing, this is handled in vvSlicerManagerCommand + break; + default: + this->Superclass::OnChar(); + break; + } +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::OnMouseWheelForward() +{ + this->FindPokedRenderer(this->Interactor->GetEventPosition()[0], + this->Interactor->GetEventPosition()[1]); + if (this->CurrentRenderer == NULL) + { + return; + } + this->GrabFocus(this->EventCallbackCommand); + if (this->Interactor->GetControlKey()) + { + this->StartDolly(); + double factor = this->MotionFactor * 0.2 * this->MouseWheelMotionFactor; + this->Dolly(pow((double)1.1, factor)); + this->EndDolly(); + } + this->ReleaseFocus(); + this->InvokeEvent(vtkCommand::MouseWheelForwardEvent, this); +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::OnMouseWheelBackward() +{ + this->FindPokedRenderer(this->Interactor->GetEventPosition()[0], + this->Interactor->GetEventPosition()[1]); + if (this->CurrentRenderer == NULL) + { + return; + } + + this->GrabFocus(this->EventCallbackCommand); + if (this->Interactor->GetControlKey()) + { + this->StartDolly(); + double factor = this->MotionFactor * -0.2 * this->MouseWheelMotionFactor; + this->Dolly(pow((double)1.1, factor)); + this->EndDolly(); + } + this->ReleaseFocus(); + this->InvokeEvent(vtkCommand::MouseWheelBackwardEvent, this); +} + + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::WindowLevel() +{ + vtkRenderWindowInteractor *rwi = this->Interactor; + + this->WindowLevelCurrentPosition[0] = rwi->GetEventPosition()[0]; + this->WindowLevelCurrentPosition[1] = rwi->GetEventPosition()[1]; + + this->InvokeEvent(vtkCommand::WindowLevelEvent, this); +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::Pick() +{ + this->InvokeEvent(vtkCommand::PickEvent, this); +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::Pan() +{ + if (this->CurrentRenderer == NULL) + { + return; + } + + vtkRenderWindowInteractor *rwi = this->Interactor; + + double viewFocus[4], focalDepth, viewPoint[3]; + double newPickPoint[4], oldPickPoint[4], motionVector[3]; + + // Calculate the focal depth since we'll be using it a lot + + vtkCamera *camera = this->CurrentRenderer->GetActiveCamera(); + camera->GetFocalPoint(viewFocus); + this->ComputeWorldToDisplay(viewFocus[0], viewFocus[1], viewFocus[2], + viewFocus); + focalDepth = viewFocus[2]; + + this->ComputeDisplayToWorld((double)rwi->GetEventPosition()[0], + (double)rwi->GetEventPosition()[1], + focalDepth, + newPickPoint); + + // Has to recalc old mouse point since the viewport has moved, + // so can't move it outside the loop + + this->ComputeDisplayToWorld((double)rwi->GetLastEventPosition()[0], + (double)rwi->GetLastEventPosition()[1], + focalDepth, + oldPickPoint); + + // Camera motion is reversed + + motionVector[0] = oldPickPoint[0] - newPickPoint[0]; + motionVector[1] = oldPickPoint[1] - newPickPoint[1]; + motionVector[2] = oldPickPoint[2] - newPickPoint[2]; + + camera->GetFocalPoint(viewFocus); + camera->GetPosition(viewPoint); + camera->SetFocalPoint(motionVector[0] + viewFocus[0], + motionVector[1] + viewFocus[1], + motionVector[2] + viewFocus[2]); + + camera->SetPosition(motionVector[0] + viewPoint[0], + motionVector[1] + viewPoint[1], + motionVector[2] + viewPoint[2]); + + if (rwi->GetLightFollowCamera()) + { + this->CurrentRenderer->UpdateLightsGeometryToFollowCamera(); + } + + rwi->Render(); +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::Dolly() +{ + if (this->CurrentRenderer == NULL) + { + return; + } + + vtkRenderWindowInteractor *rwi = this->Interactor; + double *center = this->CurrentRenderer->GetCenter(); + int dy = rwi->GetEventPosition()[1] - rwi->GetLastEventPosition()[1]; + double dyf = this->MotionFactor * (double)(dy) / (double)(center[1]); + this->Dolly(pow((double)1.1, dyf)); +} + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::Dolly(double factor) +{ + if (this->CurrentRenderer == NULL) + { + return; + } + + double viewFocus[4],viewPoint[4],motionVector[3], focalDepth; + double oldPos[3], newPos[3], distance[2]; + vtkCamera *camera = this->CurrentRenderer->GetActiveCamera(); + camera->GetFocalPoint(viewFocus); + this->ComputeWorldToDisplay(viewFocus[0], viewFocus[1], viewFocus[2], + viewFocus); + focalDepth = viewFocus[2]; + + oldPos[0] = this->CurrentRenderer->GetCenter()[0]; + oldPos[1] = this->CurrentRenderer->GetCenter()[1]; + oldPos[2] = focalDepth; + + distance[0] = 1/factor* + (this->Interactor->GetEventPosition()[0]-this->CurrentRenderer->GetCenter()[0]); + distance[1] = 1/factor* + (this->Interactor->GetEventPosition()[1]-this->CurrentRenderer->GetCenter()[1]); + + newPos[0] = this->Interactor->GetEventPosition()[0] - distance[0]; + newPos[1] = this->Interactor->GetEventPosition()[1] - distance[1]; + newPos[2] = focalDepth; + + this->CurrentRenderer->DisplayToNormalizedDisplay(oldPos[0],oldPos[1]); + this->CurrentRenderer->NormalizedDisplayToViewport(oldPos[0],oldPos[1]); + this->CurrentRenderer->ViewportToNormalizedViewport(oldPos[0],oldPos[1]); + this->CurrentRenderer->NormalizedViewportToView(oldPos[0],oldPos[1],oldPos[2]); + this->CurrentRenderer->ViewToWorld(oldPos[0],oldPos[1],oldPos[2]); + + this->CurrentRenderer->DisplayToNormalizedDisplay(newPos[0],newPos[1]); + this->CurrentRenderer->NormalizedDisplayToViewport(newPos[0],newPos[1]); + this->CurrentRenderer->ViewportToNormalizedViewport(newPos[0],newPos[1]); + this->CurrentRenderer->NormalizedViewportToView(newPos[0],newPos[1],newPos[2]); + this->CurrentRenderer->ViewToWorld(newPos[0],newPos[1],newPos[2]); + + motionVector[0] = newPos[0] - oldPos[0]; + motionVector[1] = newPos[1] - oldPos[1]; + motionVector[2] = newPos[2] - oldPos[2]; + + camera->GetFocalPoint(viewFocus); + camera->GetPosition(viewPoint); + camera->SetFocalPoint(motionVector[0] + viewFocus[0], + motionVector[1] + viewFocus[1], + motionVector[2] + viewFocus[2]); + + camera->SetPosition(motionVector[0] + viewPoint[0], + motionVector[1] + viewPoint[1], + motionVector[2] + viewPoint[2]); + + if (camera->GetParallelProjection()) + { + camera->SetParallelScale(camera->GetParallelScale() / factor); + } + else + { + camera->Dolly(factor); + if (this->AutoAdjustCameraClippingRange) + { + this->CurrentRenderer->ResetCameraClippingRange(); + } + } + + if (this->Interactor->GetLightFollowCamera()) + { + this->CurrentRenderer->UpdateLightsGeometryToFollowCamera(); + } + this->CurrentRenderer->ResetCameraClippingRange(); + //this->Interactor->Render(); +} + + +//---------------------------------------------------------------------------- +void vvInteractorStyleNavigator::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); + + os << indent << "Window Level Current Position: (" + << this->WindowLevelCurrentPosition[0] << ", " + << this->WindowLevelCurrentPosition[1] << ")" << endl; + + os << indent << "Window Level Start Position: (" + << this->WindowLevelStartPosition[0] << ", " + << this->WindowLevelStartPosition[1] << ")" << endl; +} diff --git a/vv/vvInteractorStyleNavigator.h b/vv/vvInteractorStyleNavigator.h new file mode 100644 index 0000000..3059277 --- /dev/null +++ b/vv/vvInteractorStyleNavigator.h @@ -0,0 +1,109 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvInteractorStyleNavigator.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef __vvInteractorStyleNavigator_h +#define __vvInteractorStyleNavigator_h + +#include "vtkInteractorStyle.h" + +// Motion flags + +#define VTKIS_WINDOW_LEVEL 1024 +#define VTKIS_PICK 1025 + +class vvInteractorStyleNavigator : public vtkInteractorStyle + +{ +public: + static vvInteractorStyleNavigator *New(); + vtkTypeRevisionMacro(vvInteractorStyleNavigator, vtkInteractorStyle); + void PrintSelf(ostream& os, vtkIndent indent); + + // Description: + // Some useful information for handling window level + vtkGetVector2Macro(WindowLevelStartPosition,int); + vtkGetVector2Macro(WindowLevelCurrentPosition,int); + + // Description: + // Event bindings controlling the effects of pressing mouse buttons + // or moving the mouse. + virtual void OnMouseMove(); + virtual void OnLeftButtonDown(); + virtual void OnLeftButtonUp(); + virtual void OnRightButtonDown(); + virtual void OnRightButtonUp(); + virtual void OnMiddleButtonDown(); + virtual void OnMiddleButtonUp(); + virtual void OnEnter(); + virtual void OnLeave(); + virtual void OnMouseWheelForward(); + virtual void OnMouseWheelBackward(); + + // Description: + // Override the "fly-to" (f keypress) for images. + virtual void OnChar(); + + // These methods for the different interactions in different modes + // are overridden in subclasses to perform the correct motion. Since + // they might be called from OnTimer, they do not have mouse coord parameters + // (use interactor's GetEventPosition and GetLastEventPosition) + virtual void WindowLevel(); + virtual void Pick(); + + // Interaction mode entry points used internally. + virtual void StartWindowLevel(); + virtual void EndWindowLevel(); + virtual void StartPick(); + virtual void EndPick(); + virtual void Dolly(); + virtual void Pan(); + + // We need to reimplement this because otherwise it returns the top renderer, + // not the active one + virtual void FindPokedRenderer(int, int); + +protected: + vvInteractorStyleNavigator(); + ~vvInteractorStyleNavigator(); + + static void ProcessEvents(vtkObject* object, + unsigned long event, + void* clientdata, + void* calldata); + + double MotionFactor; + + virtual void Dolly(double factor); + + int WindowLevelStartPosition[2]; + int WindowLevelCurrentPosition[2]; + +private: + vvInteractorStyleNavigator(const vvInteractorStyleNavigator&); // Not implemented. + void operator=(const vvInteractorStyleNavigator&); // Not implemented. +}; + +#endif diff --git a/vv/vvLandmarks.cxx b/vv/vvLandmarks.cxx new file mode 100644 index 0000000..7a8f8cb --- /dev/null +++ b/vv/vvLandmarks.cxx @@ -0,0 +1,285 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvLandmarks.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#include "vvLandmarks.h" + +#include +#include +#include +#include +#include + +#include "vtkPolyData.h" +#include "vtkPoints.h" +#include "vtkFloatArray.h" +#include "vtkPointData.h" +#include "clitkCommon.h" + +vvLandmarks::vvLandmarks(int size) +{ + mLandmarks.resize(0); + mFilename = ""; + + for (int i = 0; i < size; i++) + { + vtkPoints *points = vtkPoints::New(); + mPoints.push_back(points); + } + mPolyData = vtkPolyData::New(); + mIds = vtkFloatArray::New(); +} + +vvLandmarks::~vvLandmarks() +{ + for (unsigned int i = 0; i < mPoints.size(); i++) { + mPoints[i]->Delete(); + } + /*for(unsigned int i = 0; i < mText.size(); i++) { + mText[i]->Delete(); + }*/ + if (mIds) + mIds->Delete(); + if (mPolyData) + mPolyData->Delete(); +} + +void vvLandmarks::AddLandmark(float x,float y,float z,float t,double value) +{ + vvLandmark point; + point.coordinates[0] = x; + point.coordinates[1] = y; + point.coordinates[2] = z; + point.coordinates[3] = t; + point.pixel_value=value; + mLandmarks.push_back(point); + mPoints[int(t)]->InsertNextPoint(x,y,z); + + /*std::stringstream numberVal; + numberVal << (mLandmarks.size()-1); + vvLandmarksGlyph *number = vvLandmarksGlyph::New(); + number->SetText(numberVal.str().c_str()); + number->BackingOff(); + mText.push_back(number);*/ + mIds->InsertNextTuple1(0.55); + //mIds->InsertTuple1(mLandmarks.size(),mLandmarks.size()); + SetTime(int(t)); +} + +void vvLandmarks::RemoveLastLandmark() +{ + mPoints[mLandmarks.back().coordinates[3]]->SetNumberOfPoints( + mPoints[mLandmarks.back().coordinates[3]]->GetNumberOfPoints()-1); + mPolyData->Modified(); + //mText.pop_back(); + mLandmarks.pop_back(); + mIds->RemoveLastTuple(); +} + +void vvLandmarks::ChangeComments(int index, std::string comments) +{ + mLandmarks[index].comments = comments; +} + +double vvLandmarks::GetPixelValue(int index) +{ + return mLandmarks[index].pixel_value; +} + +float* vvLandmarks::GetCoordinates(int index) +{ + return mLandmarks[index].coordinates; +} + +std::string vvLandmarks::GetComments(int index) +{ + return mLandmarks[index].comments; +} + +void vvLandmarks::LoadFile(std::string filename) +{ + std::ifstream fp(filename.c_str(), std::ios::in|std::ios::binary); + if (!fp.is_open()) + { + std::cerr <<"Unable to open file " << filename << std::endl; + return; + } + mFilename = filename; + mLandmarks.clear(); + char line[255]; + for (unsigned int i = 0; i < mPoints.size();i++) + mPoints[i]->SetNumberOfPoints(0); + bool first_line=true; + while (fp.getline(line,255)) + { + std::string stringline = line; + if (first_line) + { + first_line=false; + ///New landmark format: first line is "LANDMARKSXX", where XX is the version number + if (stringline.size() >= 10 && stringline.compare(0,9,"LANDMARKS")==0) + { + std::istringstream ss(stringline.c_str()+9); + ss >> mFormatVersion; + continue; //skip first line + } + else + mFormatVersion=0; + } + DD(mFormatVersion); + if (stringline.size() > 1) + { + vvLandmark point; + int previousSpace = 0; + int space=0; + if (mFormatVersion>0) + { + space = stringline.find(" ", previousSpace+1); + if (space < -1 || space > (int)stringline.size()) + { + ErrorMsg(mLandmarks.size(),"index"); + continue; + } + //int index = atoi(stringline.substr(previousSpace,space - previousSpace).c_str()); + previousSpace = space; + } + space = stringline.find(" ", previousSpace+1); + if (space < -1 || space > (int)stringline.size()) + { + ErrorMsg(mLandmarks.size(),"x position"); + continue; + } + point.coordinates[0] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str()); + previousSpace = space; + space = stringline.find(" ", previousSpace+1); + if (space < -1 || space > (int)stringline.size()) + { + ErrorMsg(mLandmarks.size(),"y position"); + continue; + } + point.coordinates[1] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str()); + previousSpace = space; + space = stringline.find(" ", previousSpace+1); + if (space < -1 || space > (int)stringline.size()) + { + ErrorMsg(mLandmarks.size(),"z position"); + continue; + } + point.coordinates[2] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str()); + previousSpace = space; + if (mFormatVersion>0) + { + space = stringline.find(" ", previousSpace+1); + if (space < -1 || space > (int)stringline.size()) + { + ErrorMsg(mLandmarks.size(),"t position"); + continue; + } + point.coordinates[3] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str()); + previousSpace = space; + space = stringline.find(" ", previousSpace+1); + if (space < -1 || space > (int)stringline.size()) + { + ErrorMsg(mLandmarks.size(),"pixel value"); + continue; + } + point.pixel_value = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str()); + } + else + { + point.pixel_value=0.; //Not in file + point.coordinates[3]=0.; + } + previousSpace = space; + //this is the maximum size of comments + space = (stringline.find("\n", previousSpace+1) < 254 ? stringline.find("\n", previousSpace+1) : 254); + point.comments = stringline.substr(previousSpace,space - (previousSpace)).c_str(); + mLandmarks.push_back(point); + mIds->InsertNextTuple1(0.55); + mPoints[int(point.coordinates[3])]->InsertNextPoint( + point.coordinates[0],point.coordinates[1],point.coordinates[2]); + } + } + SetTime(0); +} + +bool vvLandmarks::ErrorMsg(int num,const char * text) +{ + std::cerr << "error when loading point " << num << " at " << text << std::endl; + return false; +} + +void vvLandmarks::SaveFile(std::string filename) +{ + std::string fileContent = "LANDMARKS1\n"; //File format version identification + for (unsigned int i = 0; i < mLandmarks.size(); i++) { + std::stringstream out; + out.imbue(std::locale("C")); //This is to specify that the dot is to be used as the decimal separator + out << i << " " + << mLandmarks[i].coordinates[0] << " " + << mLandmarks[i].coordinates[1] << " " + << mLandmarks[i].coordinates[2] << " " + << mLandmarks[i].coordinates[3] << " " + << mLandmarks[i].pixel_value << " "; + fileContent += out.str(); + if (mLandmarks[i].comments.size() == 0) + fileContent += " "; + else + fileContent += mLandmarks[i].comments; + fileContent += "\n"; + } + std::ofstream fp(filename.c_str(), std::ios::trunc); + if ( !fp ) + { + std::cerr << "Unable to open file" << std::endl; + return; + } + fp << fileContent.c_str()<< std::endl; + fp.close(); +} + +void vvLandmarks::SetTime(int time) +{ + if (time >= 0 && time <= ((int)mPoints.size() -1)) + { + mPolyData->SetPoints(mPoints[time]); + mPolyData->GetPointData()->SetScalars(mIds); + mPolyData->Modified(); + mPolyData->Update(); + } +} + +std::string vvLandmarks::replace_dots(std::string input) +{ + ///Replaces the dots used in the file with the decimal separator in use on the platform + lconv * conv=localeconv(); + unsigned int position = input.find( "." ); + while ( position < input.size() ) + { + input.replace(position, 1, conv->decimal_point); + position = input.find( ".", position + 1 ); + } + return input; +} diff --git a/vv/vvLandmarks.h b/vv/vvLandmarks.h new file mode 100644 index 0000000..2037653 --- /dev/null +++ b/vv/vvLandmarks.h @@ -0,0 +1,85 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvLandmarks.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:58 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvLandmarks_h +#define vvLandmarks_h + +#include +#include + +#include "vtkFloatArray.h" +#include "vtkPolyData.h" +#include "vtkPoints.h" +#include "vvLandmarksGlyph.h" + +//typedef +struct vvLandmark { + float coordinates[4]; + std::string comments; + double pixel_value; +}; + +class vvLandmarks +{ +public : + vvLandmarks(int size); + ~vvLandmarks(); + + void LoadFile(std::string filename); + void SaveFile(std::string filename); + + void AddLandmark(float x,float y,float z,float t,double value); + void RemoveLastLandmark(); + void ChangeComments(int index, std::string comments); + float* GetCoordinates(int index); + double GetPixelValue(int index); + std::string GetComments(int index); + int GetNumberOfPoints() { + return mLandmarks.size(); + } + //int GetNumberOfSources(){return mText.size();} + + vtkPolyData* GetOutput() { + return mPolyData; + } + //vtkPolyData* GetSources(int i){return mText[i]->GetOutput();} + void SetTime(int time); + + bool ErrorMsg(int num,const char * text); + +private: + ///Helper function to tackle the use of the comma as the decimal separator + std::string replace_dots(std::string input); + std::vector mLandmarks; + vtkPolyData *mPolyData; + std::vector mPoints; + vtkFloatArray* mIds; + //std::vector mText; + std::string mFilename; + int mFormatVersion; +}; + +#endif diff --git a/vv/vvLandmarksGlyph.cxx b/vv/vvLandmarksGlyph.cxx new file mode 100644 index 0000000..fe2c53c --- /dev/null +++ b/vv/vvLandmarksGlyph.cxx @@ -0,0 +1,568 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: vvLandmarksGlyph.cxx,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vvLandmarksGlyph.h" + +#include "vtkCellArray.h" +#include "vtkInformation.h" +#include "vtkInformationVector.h" +#include "vtkObjectFactory.h" +#include "vtkPointData.h" +#include "vtkPoints.h" +#include "vtkPolyData.h" +#include "vtkUnsignedCharArray.h" +#include + +vtkCxxRevisionMacro(vvLandmarksGlyph, "$Revision: 1.1 $"); +vtkStandardNewMacro(vvLandmarksGlyph); + +#define vtkfont_width 9 +//#define vtkfont_width 14 +#define vtkfont_row_width 864 +#define vtkfont_height 15 +//#define vtkfont_height 20 +static unsigned char vtkfont_bits[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xe0,0x00,0x10,0x90,0x00,0x00,0x40,0x88,0x03,0x1c,0x10,0x08,0x00, + 0x00,0x00,0x00,0x00,0x00,0x20,0x1c,0x10,0xf8,0xf8,0x03,0xe2,0x0f,0x8f,0x3f, + 0x3e,0x7c,0x00,0x00,0x00,0x02,0x80,0x00,0x1f,0x3e,0x10,0xfc,0xf0,0xf1,0xe3, + 0xcf,0x1f,0x1f,0x41,0x7c,0xe0,0x09,0x12,0x20,0x48,0x10,0x1f,0x3f,0x7c,0xfc, + 0xf0,0xf1,0x27,0x48,0x90,0x20,0x41,0x82,0xfc,0xe1,0x11,0xc0,0x03,0x02,0x00, + 0x0e,0x00,0x04,0x00,0x00,0x04,0x00,0x0e,0x00,0x01,0x00,0x00,0x08,0xc0,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x80,0x83,0xe0,0x80,0x11,0xe0,0x00,0x10,0x90,0x90,0x80,0xa0,0x44,0x04,0x0c, + 0x08,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x22,0x18,0x04,0x01,0x02,0x23, + 0x80,0x00,0x20,0x41,0x82,0x00,0x00,0x00,0x01,0x00,0x81,0x20,0x41,0x28,0x08, + 0x09,0x22,0x44,0x80,0x80,0x20,0x41,0x10,0x80,0x08,0x11,0x20,0x48,0x90,0x20, + 0x41,0x82,0x04,0x09,0x82,0x20,0x48,0x90,0x20,0x41,0x82,0x00,0x21,0x20,0x00, + 0x02,0x05,0x00,0x0c,0x00,0x04,0x00,0x00,0x04,0x00,0x11,0x00,0x01,0x10,0x80, + 0x08,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x40,0x80,0x00,0x41,0x12,0xe0,0x00,0x10,0x90,0x90,0xe0,0xa3, + 0x44,0x04,0x02,0x08,0x10,0x00,0x40,0x00,0x00,0x00,0x00,0x10,0x41,0x14,0x04, + 0x01,0x81,0x22,0x40,0x00,0x20,0x41,0x82,0x00,0x00,0x80,0x00,0x00,0x82,0x20, + 0x41,0x44,0x08,0x09,0x20,0x44,0x80,0x80,0x00,0x41,0x10,0x80,0x88,0x10,0x60, + 0xcc,0x90,0x20,0x41,0x82,0x04,0x09,0x80,0x20,0x48,0x90,0x20,0x22,0x44,0x80, + 0x20,0x20,0x00,0x82,0x08,0x00,0x10,0x00,0x04,0x00,0x00,0x04,0x00,0x11,0x00, + 0x01,0x00,0x00,0x08,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x80,0x00,0x41,0x0c,0xe0,0x00,0x10,0x00, + 0xf8,0x91,0x40,0x42,0x04,0x00,0x04,0x20,0x88,0x40,0x00,0x00,0x00,0x00,0x08, + 0x41,0x10,0x00,0x81,0x40,0xa2,0x47,0x00,0x10,0x41,0x82,0x20,0x40,0x40,0x00, + 0x00,0x04,0x20,0x79,0x82,0x08,0x09,0x20,0x44,0x80,0x80,0x00,0x41,0x10,0x80, + 0x48,0x10,0xa0,0x4a,0x91,0x20,0x41,0x82,0x04,0x09,0x80,0x20,0x88,0x88,0x20, + 0x14,0x28,0x40,0x20,0x40,0x00,0x42,0x10,0x00,0x00,0x7c,0xf4,0xf0,0xe1,0xc5, + 0x07,0x01,0x2f,0x3d,0x18,0xe0,0x08,0x82,0xe0,0x46,0x0f,0x1f,0x3d,0xbc,0xe4, + 0xf0,0xf1,0x23,0x44,0x90,0x20,0x41,0x42,0xfc,0x81,0x80,0x80,0x00,0x00,0xe0, + 0x00,0x10,0x00,0x90,0x90,0x00,0x81,0x03,0x00,0x04,0x20,0x50,0x40,0x00,0x00, + 0x00,0x00,0x04,0x41,0x10,0x80,0xc0,0x21,0x62,0x48,0x0f,0x08,0x3e,0xc2,0x70, + 0xe0,0x20,0xe0,0x0f,0x08,0x10,0x45,0x82,0xf8,0x08,0x20,0xc4,0x83,0x87,0x00, + 0x7f,0x10,0x80,0x38,0x10,0xa0,0x4a,0x92,0x20,0x3f,0x82,0xfc,0xf0,0x81,0x20, + 0x88,0x88,0x24,0x08,0x10,0x20,0x20,0x80,0x00,0x02,0x00,0x00,0x00,0x80,0x0c, + 0x09,0x12,0x26,0x08,0x81,0x10,0x43,0x10,0x80,0x88,0x81,0x20,0xc9,0x90,0x20, + 0x43,0xc2,0x18,0x09,0x42,0x20,0x44,0x90,0x20,0x22,0x42,0x80,0x60,0x80,0x00, + 0x03,0x00,0xe0,0x00,0x10,0x00,0x90,0xe0,0x03,0x41,0x04,0x00,0x04,0x20,0xfc, + 0xf9,0x03,0xe0,0x0f,0x00,0x04,0x41,0x10,0x40,0x00,0x12,0x02,0xc8,0x10,0x04, + 0x41,0xbc,0x20,0x40,0x20,0x00,0x00,0x08,0x08,0x65,0x82,0x08,0x09,0x20,0x44, + 0x80,0x80,0x38,0x41,0x10,0x80,0x28,0x10,0x20,0x49,0x94,0x20,0x01,0x82,0x24, + 0x00,0x82,0x20,0x88,0x88,0x24,0x08,0x10,0x10,0x20,0x80,0x00,0x02,0x00,0x00, + 0x00,0x80,0x04,0x09,0x10,0x24,0xc8,0x87,0x10,0x41,0x10,0x80,0x68,0x80,0x20, + 0x49,0x90,0x20,0x41,0x82,0x08,0x09,0x40,0x20,0x84,0x88,0x24,0x14,0x42,0x40, + 0x60,0x80,0x00,0x03,0x00,0xe0,0x00,0x10,0x00,0xf8,0x81,0x84,0x44,0x14,0x00, + 0x04,0x20,0x50,0x40,0x00,0x00,0x00,0x00,0x02,0x41,0x10,0x30,0x00,0xf2,0x07, + 0x48,0x10,0x02,0x41,0x80,0x00,0x00,0x40,0x00,0x00,0x04,0x04,0x59,0xfe,0x08, + 0x09,0x20,0x44,0x80,0x80,0x20,0x41,0x10,0x80,0x48,0x10,0x20,0x49,0x98,0x20, + 0x01,0x82,0x44,0x00,0x82,0x20,0x08,0x85,0x24,0x14,0x10,0x08,0x20,0x00,0x01, + 0x02,0x00,0x00,0x00,0xfc,0x04,0x09,0x10,0xe4,0x0f,0x81,0x10,0x41,0x10,0x80, + 0x18,0x80,0x20,0x49,0x90,0x20,0x41,0x82,0x08,0xf0,0x41,0x20,0x84,0x88,0x24, + 0x08,0x42,0x20,0x80,0x80,0x80,0x00,0x00,0xe0,0x00,0x10,0x00,0x90,0x80,0x44, + 0x4a,0x08,0x00,0x08,0x10,0x88,0x40,0x00,0x00,0x00,0x00,0x01,0x41,0x10,0x08, + 0x00,0x02,0x02,0x48,0x10,0x02,0x41,0x80,0x00,0x00,0x80,0xe0,0x0f,0x02,0x04, + 0x01,0x82,0x08,0x09,0x20,0x44,0x80,0x80,0x20,0x41,0x10,0x80,0x88,0x10,0x20, + 0x48,0x90,0x20,0x01,0x92,0x84,0x00,0x82,0x20,0x08,0x85,0x24,0x22,0x10,0x04, + 0x20,0x00,0x02,0x02,0x00,0x00,0x00,0x82,0x04,0x09,0x10,0x24,0x00,0x01,0x0f, + 0x41,0x10,0x80,0x68,0x80,0x20,0x49,0x90,0x20,0x41,0x82,0x08,0x00,0x42,0x20, + 0x04,0x85,0x24,0x14,0x42,0x10,0x40,0x80,0x00,0x01,0x00,0xe0,0x00,0x00,0x00, + 0x90,0xe0,0x43,0x4a,0x0c,0x00,0x08,0x10,0x00,0x40,0xc0,0x01,0x00,0x02,0x01, + 0x22,0x10,0x04,0x08,0x02,0x22,0x48,0x10,0x01,0x41,0x40,0x20,0xe0,0x00,0x01, + 0x00,0x01,0x00,0x01,0x82,0x08,0x09,0x22,0x44,0x80,0x80,0x20,0x41,0x10,0x84, + 0x08,0x11,0x20,0x48,0x90,0x20,0x01,0xa2,0x04,0x09,0x82,0x20,0x08,0x85,0x2a, + 0x41,0x10,0x04,0x20,0x00,0x02,0x02,0x00,0x00,0x00,0xc2,0x0c,0x09,0x12,0x26, + 0x00,0x81,0x00,0x41,0x10,0x80,0x88,0x81,0x20,0x49,0x90,0x20,0x43,0xc2,0x08, + 0x08,0x42,0x24,0x04,0x85,0x2a,0x22,0x62,0x08,0x40,0x80,0x00,0x01,0x00,0xe0, + 0x00,0x10,0x00,0x00,0x80,0x20,0x84,0x13,0x00,0x10,0x08,0x00,0x00,0xc0,0x00, + 0x00,0x87,0x00,0x1c,0x7c,0xfc,0xf1,0x01,0xc2,0x87,0x0f,0x01,0x3e,0x3c,0x70, + 0x60,0x00,0x02,0x80,0x00,0x04,0x3e,0x82,0xfc,0xf0,0xf1,0xe3,0x8f,0x00,0x1f, + 0x41,0x7c,0x78,0x08,0xf2,0x27,0x48,0x10,0x1f,0x01,0x7c,0x04,0xf1,0x81,0xc0, + 0x07,0x02,0x11,0x41,0x10,0xfc,0xe1,0x01,0xc4,0x03,0x00,0x00,0x00,0xbc,0xf4, + 0xf0,0xe1,0xc5,0x07,0x01,0x1f,0x41,0x7c,0x84,0x08,0xe2,0x23,0x48,0x10,0x1f, + 0x3d,0xbc,0x08,0xf0,0x81,0xc3,0x0b,0x02,0x11,0x41,0x5c,0xfc,0x81,0x83,0xe0, + 0x00,0x00,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x3f, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x20,0x00,0x00,0x84,0x00,0x00,0x00, + 0x00,0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00, + 0x00,0x00,0x00,0x00,0x00,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x20,0x00,0x00,0x84, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f, + 0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0 +}; + +// Construct object with no string set and backing enabled. +vvLandmarksGlyph::vvLandmarksGlyph() +{ + this->Text = NULL; + this->Backing = 1; + this->ForegroundColor[0] = 1.0; + this->ForegroundColor[1] = 1.0; + this->ForegroundColor[2] = 1.0; + this->ForegroundColor[3] = 1.0; + this->BackgroundColor[0] = 0.0; + this->BackgroundColor[1] = 0.0; + this->BackgroundColor[2] = 0.0; + this->BackgroundColor[3] = 1.0; + + this->SetNumberOfInputPorts(0); +} + +vvLandmarksGlyph::~vvLandmarksGlyph() +{ + if (this->Text) + { + delete [] this->Text; + } +} + +int vvLandmarksGlyph::RequestData( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **vtkNotUsed(inputVector), + vtkInformationVector *outputVector) +{ + // get the info object + vtkInformation *outInfo = outputVector->GetInformationObject(0); + + // get the ouptut + vtkPolyData *output = vtkPolyData::SafeDownCast( + outInfo->Get(vtkDataObject::DATA_OBJECT())); + + vtkPoints *newPoints; + vtkCellArray *newPolys; + vtkCellArray *newLines; + vtkUnsignedCharArray *newScalars; + + newPoints = vtkPoints::New(); + newPolys = vtkCellArray::New(); + newScalars = vtkUnsignedCharArray::New(); + newScalars->SetNumberOfComponents(4); + newLines = vtkCellArray::New(); + newLines->Allocate(newLines->EstimateSize(3,2)); + + AddTextGlyph(newPoints,newScalars,newPolys,0); + AddTextGlyph(newPoints,newScalars,newPolys,1); + AddTextGlyph(newPoints,newScalars,newPolys,2); + + AddCrossGlyph(newPoints, newLines); + + output->SetPoints(newPoints); + newPoints->Delete(); + + output->SetLines(newLines); + newLines->Delete(); + + output->GetPointData()->SetScalars(newScalars); + newScalars->Delete(); + + output->SetPolys(newPolys); + newPolys->Delete(); + + return 1; +} + +void vvLandmarksGlyph::AddTextGlyph(vtkPoints* newPoints,vtkUnsignedCharArray* newScalars, vtkCellArray *newPolys, int orientation) +{ + int row, col; + int pos = 0; + int pixelPos; + vtkIdType pts[5]; + vtkIdType numPolys = 0; + double x[3]; + int acol; + int drawingWhite = 0; + int drawingBlack = 0; + unsigned char white[4]; + unsigned char black[4]; + std::cout << "AddTextGlyph(output," << orientation << ")" << std::endl; + + if (this->Text == NULL) + { + vtkErrorMacro (<< "Text is not set!"); + return; + } + + // convert colors to unsigned char + for (int i = 0; i < 4; i++) + { + white[i] = (unsigned char) (this->ForegroundColor[i] * 255.0); + black[i] = (unsigned char) (this->BackgroundColor[i] * 255.0); + } + + std::cout << "Create Text" << std::endl; + // Create Text + while (this->Text[pos]) + { + if (this->Text[pos] != 32) + { + for (col = 0; col < vtkfont_width; col++) + { + acol = (this->Text[pos] - 32)*vtkfont_width + col - 1; + for (row = 0; row < vtkfont_height; row++) + { + pixelPos = acol + row*vtkfont_row_width; + if (vtkfont_bits[pixelPos/8] & (0x01 << pixelPos%8)) + { + if (drawingBlack) + { + x[0] = pos*vtkfont_width + col + 1; + x[1] = vtkfont_height - row; + x[2] = 0; + ChangeOrientation(x,orientation); + newPoints->InsertNextPoint(x); + newScalars->InsertNextValue(black[0]); + newScalars->InsertNextValue(black[1]); + newScalars->InsertNextValue(black[2]); + newScalars->InsertNextValue(black[3]); + + x[0] = pos*vtkfont_width + col; + x[1] = vtkfont_height - row; + x[2] = 0; + ChangeOrientation(x,orientation); + newPoints->InsertNextPoint(x); + newScalars->InsertNextValue(black[0]); + newScalars->InsertNextValue(black[1]); + newScalars->InsertNextValue(black[2]); + newScalars->InsertNextValue(black[3]); + + pts[0] = numPolys*4; + pts[1] = numPolys*4 + 1; + pts[2] = numPolys*4 + 2; + pts[3] = numPolys*4 + 3; + newPolys->InsertNextCell(4,pts); + numPolys++; + drawingBlack = 0; + } + if (!drawingWhite) + { + x[0] = pos*vtkfont_width + col; + x[1] = vtkfont_height - row; + x[2] = 0; + ChangeOrientation(x,orientation); + newPoints->InsertNextPoint(x); + newScalars->InsertNextValue(white[0]); + newScalars->InsertNextValue(white[1]); + newScalars->InsertNextValue(white[2]); + newScalars->InsertNextValue(white[3]); + + x[0] = pos*vtkfont_width + col + 1; + x[1] = vtkfont_height - row; + x[2] = 0; + ChangeOrientation(x,orientation); + newPoints->InsertNextPoint(x); + newScalars->InsertNextValue(white[0]); + newScalars->InsertNextValue(white[1]); + newScalars->InsertNextValue(white[2]); + newScalars->InsertNextValue(white[3]); + drawingWhite = 1; + } + } + // if the pixel is not set the close up the rectangle + else + { + if (drawingWhite) + { + x[0] = pos*vtkfont_width + col + 1; + x[1] = vtkfont_height - row; + x[2] = 0; + ChangeOrientation(x,orientation); + newPoints->InsertNextPoint(x); + newScalars->InsertNextValue(white[0]); + newScalars->InsertNextValue(white[1]); + newScalars->InsertNextValue(white[2]); + newScalars->InsertNextValue(white[3]); + + x[0] = pos*vtkfont_width + col; + x[1] = vtkfont_height - row; + x[2] = 0; + ChangeOrientation(x,orientation); + newPoints->InsertNextPoint(x); + newScalars->InsertNextValue(white[0]); + newScalars->InsertNextValue(white[1]); + newScalars->InsertNextValue(white[2]); + newScalars->InsertNextValue(white[3]); + + pts[0] = numPolys*4; + pts[1] = numPolys*4 + 1; + pts[2] = numPolys*4 + 2; + pts[3] = numPolys*4 + 3; + newPolys->InsertNextCell(4,pts); + numPolys++; + drawingWhite = 0; + } + if (!drawingBlack && this->Backing) + { + x[0] = pos*vtkfont_width + col; + x[1] = vtkfont_height - row; + x[2] = 0; + ChangeOrientation(x,orientation); + newPoints->InsertNextPoint(x); + newScalars->InsertNextValue(black[0]); + newScalars->InsertNextValue(black[1]); + newScalars->InsertNextValue(black[2]); + newScalars->InsertNextValue(black[3]); + + x[0] = pos*vtkfont_width + col + 1; + x[1] = vtkfont_height - row; + x[2] = 0; + ChangeOrientation(x,orientation); + newPoints->InsertNextPoint(x); + newScalars->InsertNextValue(black[0]); + newScalars->InsertNextValue(black[1]); + newScalars->InsertNextValue(black[2]); + newScalars->InsertNextValue(black[3]); + drawingBlack = 1; + } + } + } + // if we finished up a row but are still drawing close it up + if (drawingWhite) + { + x[0] = pos*vtkfont_width + col + 1; + x[1] = 0; + x[2] = 0; + ChangeOrientation(x,orientation); + newPoints->InsertNextPoint(x); + newScalars->InsertNextValue(white[0]); + newScalars->InsertNextValue(white[1]); + newScalars->InsertNextValue(white[2]); + newScalars->InsertNextValue(white[3]); + + x[0] = pos*vtkfont_width + col; + x[1] = 0; + x[2] = 0; + ChangeOrientation(x,orientation); + newPoints->InsertNextPoint(x); + newScalars->InsertNextValue(white[0]); + newScalars->InsertNextValue(white[1]); + newScalars->InsertNextValue(white[2]); + newScalars->InsertNextValue(white[3]); + + pts[0] = numPolys*4; + pts[1] = numPolys*4 + 1; + pts[2] = numPolys*4 + 2; + pts[3] = numPolys*4 + 3; + newPolys->InsertNextCell(4,pts); + numPolys++; + drawingWhite = 0; + } + if (drawingBlack) + { + x[0] = pos*vtkfont_width + col + 1; + x[1] = 0; + x[2] = 0; + ChangeOrientation(x,orientation); + newPoints->InsertNextPoint(x); + newScalars->InsertNextValue(black[0]); + newScalars->InsertNextValue(black[1]); + newScalars->InsertNextValue(black[2]); + newScalars->InsertNextValue(black[3]); + + x[0] = pos*vtkfont_width + col; + x[1] = 0; + x[2] = 0; + ChangeOrientation(x,orientation); + newPoints->InsertNextPoint(x); + newScalars->InsertNextValue(black[0]); + newScalars->InsertNextValue(black[1]); + newScalars->InsertNextValue(black[2]); + newScalars->InsertNextValue(black[3]); + + pts[0] = numPolys*4; + pts[1] = numPolys*4 + 1; + pts[2] = numPolys*4 + 2; + pts[3] = numPolys*4 + 3; + newPolys->InsertNextCell(4,pts); + numPolys++; + drawingBlack = 0; + } + } + } + else + { + // draw a black square for a space + if (this->Backing) + { + x[0] = pos*vtkfont_width; + x[1] = vtkfont_height; + x[2] = 0; + ChangeOrientation(x,orientation); + newPoints->InsertNextPoint(x); + newScalars->InsertNextValue(black[0]); + newScalars->InsertNextValue(black[1]); + newScalars->InsertNextValue(black[2]); + newScalars->InsertNextValue(black[3]); + + x[0] = pos*vtkfont_width + vtkfont_width; + x[1] = vtkfont_height; + x[2] = 0; + ChangeOrientation(x,orientation); + newPoints->InsertNextPoint(x); + newScalars->InsertNextValue(black[0]); + newScalars->InsertNextValue(black[1]); + newScalars->InsertNextValue(black[2]); + newScalars->InsertNextValue(black[3]); + + x[0] = pos*vtkfont_width + vtkfont_width; + x[1] = 0; + x[2] = 0; + ChangeOrientation(x,orientation); + newPoints->InsertNextPoint(x); + newScalars->InsertNextValue(black[0]); + newScalars->InsertNextValue(black[1]); + newScalars->InsertNextValue(black[2]); + newScalars->InsertNextValue(black[3]); + + x[0] = pos*vtkfont_width; + x[1] = 0; + x[2] = 0; + ChangeOrientation(x,orientation); + newPoints->InsertNextPoint(x); + newScalars->InsertNextValue(black[0]); + newScalars->InsertNextValue(black[1]); + newScalars->InsertNextValue(black[2]); + newScalars->InsertNextValue(black[3]); + + pts[0] = numPolys*4; + pts[1] = numPolys*4 + 1; + pts[2] = numPolys*4 + 2; + pts[3] = numPolys*4 + 3; + newPolys->InsertNextCell(4,pts); + numPolys++; + } + } + pos++; + } +} + +void vvLandmarksGlyph::AddCrossGlyph(vtkPoints* newPts,vtkCellArray* newLines) +{ + vtkIdType ptIds[2]; + double x[3]; + std::cout << "AddCross" << std::endl; + x[0] = -10; + x[1] = 0; + x[2] = 0; + ptIds[0] = newPts->InsertNextPoint(x); + + x[0] = 10; + x[1] = 0; + x[2] = 0; + ptIds[1] = newPts->InsertNextPoint(x); + newLines->InsertNextCell(2,ptIds); + + x[0] = 0; + x[1] = -10; + x[2] = 0; + ptIds[0] = newPts->InsertNextPoint(x); + + x[0] = 0; + x[1] = 10; + x[2] = 0; + ptIds[1] = newPts->InsertNextPoint(x); + newLines->InsertNextCell(2,ptIds); + + x[0] = 0; + x[1] = 0; + x[2] = -10; + ptIds[0] = newPts->InsertNextPoint(x); + + x[0] = 0; + x[1] = 0; + x[2] = 10; + ptIds[1] = newPts->InsertNextPoint(x); + newLines->InsertNextCell(2,ptIds); +} + + +void vvLandmarksGlyph::ChangeOrientation(double v[3],int orientation) +{ + double x=0,y=0,z=0; + switch (orientation) + { + case 0: + x = v[1]; + y = v[2]; + z = v[0]; + break; + case 1: + x = v[2]; + y = v[0]; + z = v[1]; + break; + case 2: + x = v[0]; + y = v[1]; + z = v[2]; + break; + default: + assert(false); //This definitely shouldn't happen + } + v[0] = x; + v[1] = y; + v[2] = z; +} + +void vvLandmarksGlyph::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); + + os << indent << "Text: " << (this->Text ? this->Text : "(none)") << "\n"; + os << indent << "Background Drawn: " << (this->Backing ? "On\n" : "Off\n"); + os << indent << "ForegroundColor: (" << this->ForegroundColor[0] << ", " + << this->ForegroundColor[1] << ", " << this->ForegroundColor[2] << ")\n"; + os << indent << "BackgroundColor: (" << this->BackgroundColor[0] << ", " + << this->BackgroundColor[1] << ", " << this->BackgroundColor[2] << ")\n"; +} diff --git a/vv/vvLandmarksGlyph.h b/vv/vvLandmarksGlyph.h new file mode 100644 index 0000000..9b3623f --- /dev/null +++ b/vv/vvLandmarksGlyph.h @@ -0,0 +1,60 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvLandmarksGlyph.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#ifndef __vvLandmarksGlyph_h +#define __vvLandmarksGlyph_h + +#include "vtkTextSource.h" +#include "vtkPoints.h" + +class vvLandmarksGlyph : public vtkTextSource +{ +public: + vtkTypeRevisionMacro(vvLandmarksGlyph,vtkTextSource); + void PrintSelf(ostream& os, vtkIndent indent); + + // Description: + // Construct object with no string set and backing enabled. + static vvLandmarksGlyph *New(); + + +protected: + vvLandmarksGlyph(); + ~vvLandmarksGlyph(); + + void AddTextGlyph(vtkPoints* newPoints,vtkUnsignedCharArray* newScalars, vtkCellArray *newPolys, int orientation); + void AddCrossGlyph(vtkPoints* newPts,vtkCellArray* newLines); + void ChangeOrientation(double v[3], int orientation); + + int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); + +private: + vvLandmarksGlyph(const vvLandmarksGlyph&); // Not implemented. + void operator=(const vvLandmarksGlyph&); // Not implemented. +}; + +#endif diff --git a/vv/vvLandmarksPanel.cxx b/vv/vvLandmarksPanel.cxx new file mode 100644 index 0000000..4ca9c35 --- /dev/null +++ b/vv/vvLandmarksPanel.cxx @@ -0,0 +1,166 @@ +#ifndef _vvLandmarksPanel_CXX +#define _vvLandmarksPanel_CXX + +/*========================================================================= + + Program: vv + Module: $RCSfile: vvLandmarksPanel.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:58 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 200COLUMN_IMAGE_NAME +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#include "vvLandmarksPanel.h" + +#include +#include +#include "QTreePushButton.h" +#include "vvLandmarks.h" + +#include + +//==================================================================== +vvLandmarksPanel::vvLandmarksPanel(QWidget * parent):QWidget(parent) +{ + setupUi(this); + + tableWidget->verticalHeader()->hide(); + loadButton->setEnabled(0); + saveButton->setEnabled(0); + removeButton->setEnabled(0); + connect(loadButton, SIGNAL(clicked()),this,SLOT(Load())); + connect(saveButton, SIGNAL(clicked()),this,SLOT(Save())); + connect(removeButton, SIGNAL(clicked()),this,SLOT(RemoveLastPoint())); + connect(tableWidget,SIGNAL(cellChanged(int,int)),this,SLOT(CommentsChanged(int,int))); +} + +void vvLandmarksPanel::Load() +{ + QString file = QFileDialog::getOpenFileName(this,tr("Load Landmarks"), + mCurrentPath.c_str(),tr("Landmarks ( *.txt)")); + if (!file.isEmpty()) + mCurrentLandmarks->LoadFile(file.toStdString()); + SetCurrentLandmarks(mCurrentLandmarks,2); + emit UpdateRenderWindows(); +} + +void vvLandmarksPanel::Save() +{ + QString file = QFileDialog::getSaveFileName(this, + tr("Save Landmarks"), + mCurrentPath.c_str(),tr("Landmarks ( *.txt)")); + if (!file.isEmpty()) + { + std::string filename = vtksys::SystemTools::GetFilenamePath(file.toStdString()); + filename += "/" + vtksys::SystemTools::GetFilenameWithoutLastExtension(file.toStdString()); + filename += ".txt"; + mCurrentLandmarks->SaveFile(filename.c_str()); + } +} + +void vvLandmarksPanel::RemoveLastPoint() +{ + if (tableWidget->rowCount() > 0) + { + tableWidget->removeRow(tableWidget->rowCount()-1); + mCurrentLandmarks->RemoveLastLandmark(); + emit UpdateRenderWindows(); + } +} + +void vvLandmarksPanel::AddPoint() +{ + AddPoint(mCurrentLandmarks->GetNumberOfPoints()-1); +} + +void vvLandmarksPanel::AddPoint(int landmarksIndex) +{ + int rowIndex = landmarksIndex; //tableWidget->rowCount(); + tableWidget->setRowCount(rowIndex+1); + tableWidget->setRowHeight(rowIndex,20); + QTableWidgetItem* iItem = new QTableWidgetItem(QString::number(landmarksIndex)); + iItem->setFlags(!Qt::ItemIsEditable); + tableWidget->setItem(rowIndex,0,iItem); + + QTableWidgetItem* xItem = new QTableWidgetItem( + QString::number(mCurrentLandmarks->GetCoordinates(landmarksIndex)[0],'f',1)); + xItem->setFlags(!Qt::ItemIsEditable); + tableWidget->setItem(rowIndex,1,xItem); + + QTableWidgetItem* yItem = new QTableWidgetItem( + QString::number(mCurrentLandmarks->GetCoordinates(landmarksIndex)[1],'f',1)); + yItem->setFlags(!Qt::ItemIsEditable); + tableWidget->setItem(rowIndex,2,yItem); + + QTableWidgetItem* zItem = new QTableWidgetItem( + QString::number(mCurrentLandmarks->GetCoordinates(landmarksIndex)[2],'f',1)); + zItem->setFlags(!Qt::ItemIsEditable); + tableWidget->setItem(rowIndex,3,zItem); + + QTableWidgetItem* tItem = new QTableWidgetItem( + QString::number(mCurrentLandmarks->GetCoordinates(landmarksIndex)[3],'f',1)); + tItem->setFlags(!Qt::ItemIsEditable); + tableWidget->setItem(rowIndex,4,tItem); + + + QTableWidgetItem* vItem = new QTableWidgetItem( + QString::number(mCurrentLandmarks->GetPixelValue(landmarksIndex),'f',1)); + vItem->setFlags(!Qt::ItemIsEditable); + tableWidget->setItem(rowIndex,5,vItem); + + tableWidget->setItem(rowIndex,6, new QTableWidgetItem(mCurrentLandmarks->GetComments(landmarksIndex).c_str())); +} + +void vvLandmarksPanel::SetCurrentLandmarks(vvLandmarks* lm,int time) +{ + loadButton->setEnabled(1); + saveButton->setEnabled(1); + removeButton->setEnabled(1); + mCurrentLandmarks = lm; + tableWidget->clearContents(); + tableWidget->setRowCount(mCurrentLandmarks->GetNumberOfPoints()); + for (int i = 0; i < mCurrentLandmarks->GetNumberOfPoints(); i++) + AddPoint(i); + //if (time > 1) + //tableWidget->setColumnHidden(4,1); + //else + //tableWidget->setColumnHidden(4,0); + tableWidget->resizeColumnsToContents(); +} + +void vvLandmarksPanel::SetCurrentImage(std::string filename) +{ + QString image = "CurrentImage : "; + image += vtksys::SystemTools::GetFilenameWithoutLastExtension(filename).c_str(); + nameLabel->setText(image); +} + +void vvLandmarksPanel::CommentsChanged(int row, int column) +{ + if (column == 6) + { + mCurrentLandmarks->ChangeComments(row,std::string(tableWidget->item(row,column)->text().toStdString())); + tableWidget->resizeColumnsToContents(); + } +} + +#endif /* end #define _vvLandmarksPanel_CXX */ + diff --git a/vv/vvLandmarksPanel.h b/vv/vvLandmarksPanel.h new file mode 100644 index 0000000..8078404 --- /dev/null +++ b/vv/vvLandmarksPanel.h @@ -0,0 +1,70 @@ +#ifndef _vvLandmarksPanel_H +#define _vvLandmarksPanel_H + +/*========================================================================= + + Program: vv + Module: $RCSfile: vvLandmarksPanel.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 200COLUMN_IMAGE_NAME +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#include +#include +#include "vvLandmarks.h" + +#include "ui_vvLandmarksPanel.h" + +//==================================================================== +class vvLandmarksPanel : public QWidget, private Ui::vvLandmarksPanel +{ + + Q_OBJECT + +public: + // constructor - destructor + vvLandmarksPanel(QWidget * parent=0); + ~vvLandmarksPanel() {} + void SetCurrentLandmarks(vvLandmarks *lm, int time); + void SetCurrentPath(std::string path) { + mCurrentPath = path; + } + void SetCurrentImage(std::string filename); + +public slots: + void Load(); + void Save(); + void RemoveLastPoint(); + void AddPoint(); + void CommentsChanged(int row, int column); +signals: + void UpdateRenderWindows(); + +private: + void AddPoint(int); + vvLandmarks* mCurrentLandmarks; + std::string mCurrentPath; +}; // end class vvLandmarksPanel +//==================================================================== + +#endif /* end #define _vvLandmarksPanel_H */ + diff --git a/vv/vvLinkPanel.cxx b/vv/vvLinkPanel.cxx new file mode 100644 index 0000000..57f6b81 --- /dev/null +++ b/vv/vvLinkPanel.cxx @@ -0,0 +1,193 @@ +#ifndef _vvLinkPanel_CXX +#define _vvLinkPanel_CXX + +/*========================================================================= + + Program: vv + Module: $RCSfile: vvLinkPanel.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 200COLUMN_IMAGE_NAME +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#include "vvLinkPanel.h" +#include "clitkCommon.h" + +#include +#include +#include "QTreePushButton.h" + +//==================================================================== +vvLinkPanel::vvLinkPanel(QWidget * parent):QWidget(parent) +{ + setupUi(this); + imageNames.resize(0); + image1Ids.resize(0); + image2Ids.resize(0); + + linkTableWidget->resizeColumnsToContents(); + linkTableWidget->verticalHeader()->hide(); + linkTableWidget->horizontalHeader()->hide(); + linkTableWidget->hideColumn(4); + linkTableWidget->hideColumn(5); + + connect(image1ComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(UpdateComboBox2(int))); + connect(linkButton,SIGNAL(clicked()),this,SLOT(addLink())); + connect(linkAllButton,SIGNAL(clicked()),this,SLOT(linkAll())); +} + +void vvLinkPanel::addImage(std::string name, std::string id) +{ + imageNames.push_back(name); + image1Ids.push_back(id); + UpdateComboBox1(); +} + +void vvLinkPanel::removeImage(int index) +{ + std::string idRemoved = image1Ids[index]; + std::vector::iterator Nameiter = imageNames.begin(); + std::vector::iterator Iditer = image1Ids.begin(); + for (int i = 0; i < index; i++) + { + Nameiter++; + Iditer++; + } + imageNames.erase(Nameiter); + image1Ids.erase(Iditer); + UpdateComboBox1(); + for (int i = linkTableWidget->rowCount() - 1; i >= 0 ;i--) + { + if (linkTableWidget->item(i,4)->text().toStdString() == idRemoved || + linkTableWidget->item(i,5)->text().toStdString() == idRemoved) + { + emit removeLink(linkTableWidget->item(i,4)->text(),linkTableWidget->item(i,5)->text()); + linkTableWidget->removeRow(i); + UpdateComboBox2(image1ComboBox->currentIndex()); + } + } +} + +void vvLinkPanel::UpdateComboBox1() +{ + image1ComboBox->clear(); + for (unsigned int i = 0; i < imageNames.size();i++) + { + image1ComboBox->addItem(imageNames[i].c_str()); + } +} + +void vvLinkPanel::UpdateComboBox2(int index) +{ + image2ComboBox->clear(); + image2Ids.resize(0); + if (imageNames.size() > 1 && index >= 0) + { + for (unsigned int i = 0; i < imageNames.size();i++) + { + if ((int)i != index) + { + bool AlreadyLinked = false; + for (int row = 0; row < linkTableWidget->rowCount();row++) + { + if ((linkTableWidget->item(row,1)->text().toStdString() == imageNames[index] && + linkTableWidget->item(row,3)->text().toStdString() == imageNames[i]) || + (linkTableWidget->item(row,3)->text().toStdString() == imageNames[index] && + linkTableWidget->item(row,1)->text().toStdString() == imageNames[i])) + { + AlreadyLinked = true; + break; + } + } + if (!AlreadyLinked) + { + image2ComboBox->addItem(imageNames[i].c_str()); + image2Ids.push_back(image1Ids[i]); + } + } + } + } + if (image2ComboBox->count() == 0) + linkButton->setEnabled(0); + else + linkButton->setEnabled(1); +} + +void vvLinkPanel::linkAll() +{ + //First remove all links + while (linkTableWidget->rowCount()) + removeLink(1,1); + //Now create all possible links + int count=image2ComboBox->count(); + for (int j=0;jsetCurrentIndex(j); + image2ComboBox->setCurrentIndex(0); + for (int i=0;i< count-j;i++) + addLink(); + } +} + +void vvLinkPanel::addLink() +{ + if (!image1ComboBox->currentText().isEmpty() + && !image2ComboBox->currentText().isEmpty()) + { + int row = linkTableWidget->rowCount(); + linkTableWidget->insertRow(row); + + linkTableWidget->setItem(row,1,new QTableWidgetItem(image1ComboBox->currentText())); + linkTableWidget->setItem(row,2,new QTableWidgetItem("&")); + linkTableWidget->setItem(row,3,new QTableWidgetItem(image2ComboBox->currentText())); + linkTableWidget->setItem(row,4,new QTableWidgetItem(image1Ids[image1ComboBox->currentIndex()].c_str())); + linkTableWidget->setItem(row,5,new QTableWidgetItem(image2Ids[image2ComboBox->currentIndex()].c_str())); + QTreePushButton* cButton = new QTreePushButton; + cButton->setIndex(linkTableWidget->rowCount()); + cButton->setColumn(0); + cButton->setIcon(QIcon(QString::fromUtf8(":/new/prefix1/icons/exit.png"))); + connect(cButton,SIGNAL(clickedInto(int, int)), + this,SLOT(removeLink(int, int))); + cButton->setToolTip(tr("remove link")); + linkTableWidget->setCellWidget(row,0,cButton); + + linkTableWidget->resizeColumnToContents(0); + linkTableWidget->resizeColumnToContents(1); + linkTableWidget->resizeColumnToContents(2); + linkTableWidget->resizeColumnToContents(3); + linkTableWidget->setRowHeight(row,17); + + emit addLink(image1Ids[image1ComboBox->currentIndex()].c_str(), + image2Ids[image2ComboBox->currentIndex()].c_str()); + UpdateComboBox2(image1ComboBox->currentIndex()); + } + +} + +void vvLinkPanel::removeLink(int row, int column) +{ + emit removeLink(linkTableWidget->item(row-1,4)->text(),linkTableWidget->item(row-1,5)->text()); + linkTableWidget->removeRow(row-1); + UpdateComboBox2(image1ComboBox->currentIndex()); +} + +#endif /* end #define _vvLinkPanel_CXX */ + diff --git a/vv/vvLinkPanel.h b/vv/vvLinkPanel.h new file mode 100644 index 0000000..23b34bb --- /dev/null +++ b/vv/vvLinkPanel.h @@ -0,0 +1,71 @@ +#ifndef _vvLinkPanel_H +#define _vvLinkPanel_H + +/*========================================================================= + + Program: vv + Module: $RCSfile: vvLinkPanel.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 200COLUMN_IMAGE_NAME +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#include +#include + +#include "ui_vvLinkPanel.h" + +//==================================================================== +class vvLinkPanel : public QWidget, private Ui::vvLinkPanel +{ + + Q_OBJECT + +public: + // constructor - destructor + vvLinkPanel(QWidget * parent=0); + ~vvLinkPanel() {} + + void addImage(std::string name, std::string id); + void removeImage(int i); + +public slots : + void UpdateComboBox2(int i); + void removeLink(int row, int column); + void addLink(); + void linkAll(); + +signals: + void addLink(QString image1,QString image2); + void removeLink(QString image1,QString image2); + +private: + void UpdateComboBox1(); + + std::vector imageNames; + std::vector image1Ids; + std::vector image2Ids; + +}; // end class vvLinkPanel +//==================================================================== + +#endif /* end #define _vvLinkPanel_H */ + diff --git a/vv/vvMainWindow.cxx b/vv/vvMainWindow.cxx new file mode 100644 index 0000000..94dc1b5 --- /dev/null +++ b/vv/vvMainWindow.cxx @@ -0,0 +1,2686 @@ +/*========================================================================= + +Program: vv +Module: $RCSfile: vvMainWindow.cxx,v $ +Language: C++ +Date: $Date: 2010/01/06 13:31:57 $ +Version: $Revision: 1.1 $ +Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 200COLUMN_IMAGE_NAME +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#include +#include +#include +#include + +#include "vvMainWindow.h" +#include "vvHelpDialog.h" +#include "vvDocumentation.h" +#include "vvProgressDialog.h" +#include "vvQDicomSeriesSelector.h" +#include "vvSlicerManager.h" +#include "clitkIOCommon.h" +#include "vvSlicer.h" +#include "vvInteractorStyleNavigator.h" +#include "vvImageWriter.h" +#include "vvResamplerDialog.h" +#include "vvSegmentationDialog.h" +#include "vvSurfaceViewerDialog.h" +#include "vvDeformationDialog.h" +#include "vvImageWarp.h" +#include "vvUtils.h" +#include "vvMaximumIntensityProjection.h" +#include "vvMidPosition.h" +#include "vvMesh.h" +#include "vvStructSelector.h" +#include "vvMeshReader.h" +#include "vvCropDialog.h" +#include "QTreePushButton.h" + +#ifdef CLITK_VV_USE_BDCM +#include +#endif + +#include "itkImage.h" +#include "itkImageFileReader.h" +#include "itkByteSwapper.h" +#include "itkCommand.h" +#include "itkNumericSeriesFileNames.h" + +#include "vtkImageData.h" +#include "vtkImageActor.h" +#include "vtkCornerAnnotation.h" +#include "vtkRenderWindow.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkRenderer.h" +#include "vtkRendererCollection.h" + +#include "vtkWindowToImageFilter.h" +#include "vtkBMPWriter.h" +#include "vtkTIFFWriter.h" +#include "vtkPNMWriter.h" +#include "vtkPNGWriter.h" +#include "vtkJPEGWriter.h" + +// Standard includes +#include + +#include "vvConstants.h" + +#define COLUMN_TREE 0 +#define COLUMN_UL_VIEW 1 +#define COLUMN_UR_VIEW 2 +#define COLUMN_DL_VIEW 3 +#define COLUMN_DR_VIEW 4 +#define COLUMN_CLOSE_IMAGE 5 +#define COLUMN_RELOAD_IMAGE 6 +#define COLUMN_IMAGE_NAME 7 + +/*Data Tree values + 0,Qt::UserRole full filename + 1,Qt::CheckStateRole checkbutton UL View + 1,Qt::UserRole overlay, fusion or vector + 2,Qt::CheckStateRole checkbutton UR View + 3,Qt::CheckStateRole checkbutton DL View + 4,Qt::CheckStateRole checkbutton DR View + 5,0 short filename + 5,Qt::UserRole mSlicerManager id*/ + +//==================================================================== +vvMainWindow::vvMainWindow() { + setupUi(this); // this sets up the GUI + + mInputPathName = ""; + + //Init the contextMenu + this->setContextMenuPolicy(Qt::CustomContextMenu); + contextActions.resize(0); + QAction* actionOpen_new_image = contextMenu.addAction(QIcon(QString::fromUtf8(":/new/prefix1/icons/fileopen.png")), + tr("Open new Image")); + connect(actionOpen_new_image,SIGNAL(triggered()),this,SLOT(OpenImages())); + contextActions.push_back(actionOpen_new_image); + + contextMenu.addSeparator(); + + QAction* actionClose_Image = contextMenu.addAction(QIcon(QString::fromUtf8(":/new/prefix1/icons/exit.png")), + tr("Close Current Image")); + connect(actionClose_Image,SIGNAL(triggered()),this,SLOT(CloseImage())); + contextActions.push_back(actionClose_Image); + + QAction* actionReload_image = contextMenu.addAction(QIcon(QString::fromUtf8(":/new/prefix1/icons/rotateright.png")), + tr("Reload Current Image")); + connect(actionReload_image,SIGNAL(triggered()),this,SLOT(ReloadImage())); + contextActions.push_back(actionReload_image); + + QAction* actionSave_image = contextMenu.addAction(QIcon(QString::fromUtf8(":/new/prefix1/icons/filesave.png")), + tr("Save Current Image")); + connect(actionSave_image,SIGNAL(triggered()),this,SLOT(SaveAs())); + contextActions.push_back(actionSave_image); + + contextMenu.addSeparator(); + + QAction* actionCrop_image = contextMenu.addAction(QIcon(QString::fromUtf8(":/new/prefix1/icons/crop.png")), + tr("Crop Current Image")); + connect(actionCrop_image,SIGNAL(triggered()),this,SLOT(CropImage())); + contextActions.push_back(actionCrop_image); + + QAction* actionSplit_image = contextMenu.addAction(QIcon(QString::fromUtf8(":/new/prefix1/icons/cut.png")), + tr("Split Current Image")); + connect(actionSplit_image,SIGNAL(triggered()),this,SLOT(SplitImage())); + contextActions.push_back(actionSplit_image); + + contextMenu.addSeparator(); + + contextMenu.addAction(actionAdd_VF_to_current_Image); + contextActions.push_back(actionAdd_VF_to_current_Image); + + QAction* actionAdd_Overlay_to_current_Image = menuOverlay->addAction(QIcon(QString::fromUtf8(":/new/prefix1/icons/GPSup.png")), + tr("Add overlay image to current image")); + contextMenu.addAction(actionAdd_Overlay_to_current_Image); + contextActions.push_back(actionAdd_Overlay_to_current_Image); + + connect(actionAdd_Overlay_to_current_Image,SIGNAL(triggered()), this,SLOT(SelectOverlayImage())); + + contextMenu.addAction(actionAdd_fusion_image); + connect(actionAdd_fusion_image,SIGNAL(triggered()),this,SLOT(AddFusionImage())); + contextActions.push_back(actionAdd_fusion_image); + + + //init the DataTree + mSlicerManagers.resize(0); + + QStringList header; + header.append(""); + header.append("TL"); + header.append("TR"); + header.append("BL"); + header.append("BR"); + header.append(""); + header.append(""); + header.append("Name"); + + DataTree->setHeaderLabels(header); + DataTree->resizeColumnToContents(COLUMN_TREE); + DataTree->resizeColumnToContents(COLUMN_UL_VIEW); + DataTree->resizeColumnToContents(COLUMN_UR_VIEW); + DataTree->resizeColumnToContents(COLUMN_DL_VIEW); + DataTree->resizeColumnToContents(COLUMN_DR_VIEW); + DataTree->resizeColumnToContents(COLUMN_CLOSE_IMAGE); + DataTree->resizeColumnToContents(COLUMN_RELOAD_IMAGE); + DataTree->resizeColumnToContents(COLUMN_IMAGE_NAME); + + viewMode = 1; + documentation = new vvDocumentation(); + help_dialog = new vvHelpDialog(); + dicomSeriesSelector = new vvDicomSeriesSelector(); + + inverseButton->setEnabled(0); + actionAdd_Overlay_to_current_Image->setEnabled(0); + actionSave_As->setEnabled(0); + actionAdd_VF_to_current_Image->setEnabled(0); + actionAdd_fusion_image->setEnabled(0); + + //init the sliders + verticalSliders.push_back(NOVerticalSlider); + verticalSliders.push_back(NEVerticalSlider); + verticalSliders.push_back(SOVerticalSlider); + verticalSliders.push_back(SEVerticalSlider); + + for (int i =0; i < 4; i++) + verticalSliders[i]->hide(); + + horizontalSliders.push_back(NOHorizontalSlider); + horizontalSliders.push_back(NEHorizontalSlider); + horizontalSliders.push_back(SOHorizontalSlider); + horizontalSliders.push_back(SEHorizontalSlider); + + for (int i =0; i < 4; i++) + horizontalSliders[i]->hide(); + + + connect(NOVerticalSlider,SIGNAL(valueChanged(int)),this,SLOT(NOVerticalSliderChanged())); + connect(NEVerticalSlider,SIGNAL(valueChanged(int)),this,SLOT(NEVerticalSliderChanged())); + connect(SOVerticalSlider,SIGNAL(valueChanged(int)),this,SLOT(SOVerticalSliderChanged())); + connect(SEVerticalSlider,SIGNAL(valueChanged(int)),this,SLOT(SEVerticalSliderChanged())); + + connect(NOHorizontalSlider,SIGNAL(valueChanged(int)),this,SLOT(NOHorizontalSliderMoved())); + connect(NEHorizontalSlider,SIGNAL(valueChanged(int)),this,SLOT(NEHorizontalSliderMoved())); + connect(SOHorizontalSlider,SIGNAL(valueChanged(int)),this,SLOT(SOHorizontalSliderMoved())); + connect(SEHorizontalSlider,SIGNAL(valueChanged(int)),this,SLOT(SEHorizontalSliderMoved())); + + //connect everything + connect(actionMaximum_Intensity_Projection,SIGNAL(triggered()),this,SLOT(ComputeMIP())); + connect(actionCompute_mid_position_image,SIGNAL(triggered()),this,SLOT(ComputeMidPosition())); + connect(actionDeformable_Registration,SIGNAL(triggered()),this,SLOT(ComputeDeformableRegistration())); + connect(actionWarp_image_with_vector_field,SIGNAL(triggered()),this,SLOT(WarpImage())); + connect(actionLoad_images,SIGNAL(triggered()),this,SLOT(OpenImages())); + connect(actionOpen_Dicom,SIGNAL(triggered()),this,SLOT(OpenDicom())); + connect(actionOpen_Dicom_Struct,SIGNAL(triggered()),this,SLOT(OpenDCStructContour())); + connect(actionOpen_VTK_contour,SIGNAL(triggered()),this,SLOT(OpenVTKContour())); + connect(actionOpen_Multiple_Images_As_One,SIGNAL(triggered()),this,SLOT(MergeImages())); + connect(actionOpen_Image_With_Time,SIGNAL(triggered()),this,SLOT(OpenImageWithTime())); + connect(actionMerge_images_as_n_dim_t, SIGNAL(triggered()), this, SLOT(MergeImagesWithTime())); + connect(actionSave_As,SIGNAL(triggered()),this,SLOT(SaveAs())); + connect(actionExit,SIGNAL(triggered()),this,SLOT(close())); + connect(actionAdd_VF_to_current_Image,SIGNAL(triggered()),this,SLOT(OpenField())); + connect(actionNavigation_Help,SIGNAL(triggered()),this,SLOT(ShowHelpDialog())); + connect(actionDocumentation,SIGNAL(triggered()),this,SLOT(ShowDocumentation())); + + /////////////////////////////////////////////// + contextMenu.addAction(actionResampler); + connect(actionResampler,SIGNAL(triggered()),this,SLOT(ResampleCurrentImage())); + connect(actionSegmentation,SIGNAL(triggered()),this,SLOT(SegmentationOnCurrentImage())); + connect(actionSurface_Viewer,SIGNAL(triggered()),this,SLOT(SurfaceViewerLaunch())); + /////////////////////////////////////////////// + + actionNorth_East_Window->setEnabled(0); + actionNorth_West_Window->setEnabled(0); + actionSouth_East_Window->setEnabled(0); + actionSouth_West_Window->setEnabled(0); + + connect(actionNorth_East_Window,SIGNAL(triggered()),this,SLOT(SaveNEScreenshot())); + connect(actionNorth_West_Window,SIGNAL(triggered()),this,SLOT(SaveNOScreenshot())); + connect(actionSouth_East_Window,SIGNAL(triggered()),this,SLOT(SaveSEScreenshot())); + connect(actionSouth_West_Window,SIGNAL(triggered()),this,SLOT(SaveSOScreenshot())); + + connect(DataTree,SIGNAL(itemSelectionChanged()),this,SLOT(ImageInfoChanged())); + connect(DataTree,SIGNAL(itemClicked(QTreeWidgetItem*, int)),this, + SLOT(DisplayChanged(QTreeWidgetItem*, int))); + + connect(viewButton,SIGNAL(clicked()),this, SLOT(ChangeViewMode()) ); + connect(windowSpinBox,SIGNAL(editingFinished()),this,SLOT(WindowLevelEdited())); + connect(levelSpinBox,SIGNAL(editingFinished()),this,SLOT(WindowLevelEdited())); + connect(colorMapComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(UpdateColorMap())); + connect(presetComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(UpdateWindowLevel())); + connect(inverseButton,SIGNAL(clicked()),this,SLOT(SwitchWindowLevel())); + + + connect(this,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(ShowContextMenu(QPoint))); + + connect(linkPanel,SIGNAL(addLink(QString,QString)),this,SLOT(AddLink(QString,QString))); + connect(linkPanel,SIGNAL(removeLink(QString,QString)),this,SLOT(RemoveLink(QString,QString))); + connect(overlayPanel,SIGNAL(VFPropertyUpdated(int,int,int)),this,SLOT(SetVFProperty(int,int,int))); + connect(overlayPanel,SIGNAL(OverlayPropertyUpdated(int)),this,SLOT(SetOverlayProperty(int))); + connect(overlayPanel,SIGNAL(FusionPropertyUpdated(int,int,double,double)), + this,SLOT(SetFusionProperty(int,int,double,double))); + connect(landmarksPanel,SIGNAL(UpdateRenderWindows()),this,SLOT(UpdateRenderWindows())); + + playMode = 0;//pause + mFrameRate = 10; + playButton->setEnabled(0); + frameRateLabel->setEnabled(0); + frameRateSpinBox->setEnabled(0); + connect(playButton, SIGNAL(clicked()),this,SLOT(PlayPause())); + connect(frameRateSpinBox, SIGNAL(valueChanged(int)),this,SLOT(ChangeFrameRate(int))); + + goToCursorPushButton->setEnabled(0); + connect(goToCursorPushButton, SIGNAL(clicked()),this,SLOT(GoToCursor())); + + NOViewWidget->hide(); + NEViewWidget->hide(); + SOViewWidget->hide(); + SEViewWidget->hide(); + + //Recently opened files + std::list recent_files = GetRecentlyOpenedImages(); + if ( not recent_files.empty() ) + { + QMenu * rmenu = new QMenu("Recently opened files..."); + rmenu->setIcon(QIcon(QString::fromUtf8(":/new/prefix1/icons/open.png"))); + menuFile->insertMenu(actionOpen_Image_With_Time,rmenu); + for (std::list::iterator i = recent_files.begin();i!=recent_files.end();i++) + { + QAction* current=new QAction(QIcon(QString::fromUtf8(":/new/prefix1/icons/open.png")), + (*i).c_str(),this); + rmenu->addAction(current); + connect(current,SIGNAL(triggered()),this,SLOT(OpenRecentImage())); + } + } +} +//==================================================================== +void vvMainWindow::ComputeMIP() +{ + vvMaximumIntensityProjection mip; + vvSlicerManager* selected_slicer = mSlicerManagers[GetSlicerIndexFromItem(DataTree->selectedItems()[0])]; + QFileInfo info(selected_slicer->GetFileName().c_str()); + mip.Compute(selected_slicer); + AddImage(mip.GetOutput(),info.path().toStdString()+"/"+info.completeBaseName().toStdString()+"_mip.mhd"); +} + +void vvMainWindow::ComputeMidPosition() +{ + bool ok; + int index=GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + int ref = QInputDialog::getInteger(this,"Chose reference phase","Reference phase",0,0,\ + mSlicerManagers[index]->GetImage()->GetVTKImages().size()-1,1,&ok); + if (ok) + { + vvMidPosition midp; + midp.slicer_manager = mSlicerManagers[index]; + midp.reference_image_index = ref; + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + midp.Update(); + if (midp.error) + QMessageBox::warning(this, "Error computing midposition image",midp.error_message.c_str()); + else + { + QFileInfo info(midp.slicer_manager->GetFileName().c_str()); + AddImage(midp.output,info.path().toStdString()+"/"+info.completeBaseName().toStdString()+"_midposition.mhd"); + } + QApplication::restoreOverrideCursor(); + } +} + +void vvMainWindow::AddContour(int image_index, vvMesh::Pointer contour, bool propagation) +{ + QTreeWidgetItem *item = new QTreeWidgetItem(); + item->setData(0,Qt::UserRole,"filename.vtk"); + item->setData(1,Qt::UserRole,tr("contour")); + QBrush brush; + brush.setColor(QColor(contour->r*255,contour->g*255,contour->b*255)); + brush.setStyle(Qt::SolidPattern); + item->setData(COLUMN_IMAGE_NAME,Qt::BackgroundRole,brush); + item->setData(COLUMN_IMAGE_NAME,Qt::DisplayRole,contour->structure_name.c_str()); + + for (int j = 1; j <= 4; j++) + item->setData(j,Qt::CheckStateRole,DataTree->topLevelItem(image_index)->data(j,Qt::CheckStateRole)); + + QTreePushButton* cButton = new QTreePushButton; + cButton->setItem(item); + cButton->setColumn(COLUMN_CLOSE_IMAGE); + cButton->setToolTip(tr("close image")); + cButton->setIcon(QIcon(QString::fromUtf8(":/new/prefix1/icons/exit.png"))); + connect(cButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(CloseImage(QTreeWidgetItem*, int))); + + QTreePushButton* rButton = new QTreePushButton; + rButton->setItem(item); + rButton->setColumn(COLUMN_RELOAD_IMAGE); + rButton->setToolTip(tr("reload image")); + rButton->setIcon(QIcon(QString::fromUtf8(":/new/prefix1/icons/rotateright.png"))); + rButton->setEnabled(false); + //Not implemented + //connect(rButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + //this,SLOT(ReloadImage(QTreeWidgetItem*, int))); + + DataTree->topLevelItem(image_index)->setExpanded(1); + DataTree->topLevelItem(image_index)->addChild(item); + DataTree->setItemWidget(item, COLUMN_CLOSE_IMAGE, cButton); + DataTree->setItemWidget(item, COLUMN_RELOAD_IMAGE, rButton); + QString id = DataTree->topLevelItem(image_index)->data(COLUMN_IMAGE_NAME,Qt::UserRole).toString(); + item->setData(COLUMN_IMAGE_NAME,Qt::UserRole,id.toStdString().c_str()); + + UpdateTree(); + mSlicerManagers[image_index]->AddContour(contour,propagation); + mSlicerManagers[image_index]->Render(); +} + +//==================================================================== +void vvMainWindow::OpenVTKContour() +{ + if (mSlicerManagers.size() > 0) + { + QString Extensions = "Images ( *.vtk)"; + Extensions += ";;All Files (*)"; + QString file = QFileDialog::getOpenFileName(this,tr("Open vtkPolyData"),mInputPathName,Extensions); + if (file.isNull()) + return; + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + vvMeshReader reader; + reader.SetModeToVTK(); + reader.SetFilename(file.toStdString()); + reader.Update(); + AddContour(index,reader.GetOutput()[0],false); + QApplication::restoreOverrideCursor(); + } +} +//==================================================================== +void vvMainWindow::OpenDCStructContour() +{ + if (mSlicerManagers.size() > 0) + { + QString Extensions = "Dicom Files ( *.dcm)"; + Extensions += ";;All Files (*)"; + QString file = QFileDialog::getOpenFileName(this,tr("Merge Images"),mInputPathName,Extensions); + if (file.isNull()) + return; + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + vvMeshReader reader; + reader.SetFilename(file.toStdString()); + vvStructSelector selector; + selector.SetStructures(reader.GetROINames()); + if (!mSlicerManagers[index]->GetVF().IsNull()) + selector.EnablePropagationCheckBox(); + if (selector.exec()) + { + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + reader.SetSelectedItems(selector.getSelectedItems()); + reader.SetImage(mSlicerManagers[index]->GetImage()); + if (selector.PropagationEnabled()) + reader.SetPropagationVF(mSlicerManagers[index]->GetVF()); + reader.Update(); + std::vector contours=reader.GetOutput(); + for (std::vector::iterator i=contours.begin(); + i!=contours.end();i++) + AddContour(index,*i,selector.PropagationEnabled()); + QApplication::restoreOverrideCursor(); + } + } +} + +//==================================================================== +void vvMainWindow::ComputeDeformableRegistration() +{ + if (mSlicerManagers.size() > 0) + { + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + vvDeformationDialog dialog(index,mSlicerManagers); + if (dialog.exec()) + { + std::string base_name=itksys::SystemTools::GetFilenameWithoutExtension(mSlicerManagers[dialog.GetInputFileIndex()]->GetFileName()); + AddField(dialog.GetOutput(),dialog.getFieldFile(),dialog.GetInputFileIndex()); + WarpImage(dialog.GetSelectedSlicer(),dialog.GetReferenceFrameIndex()); + } + else + std::cout << "Error or user cancellation while computing deformation field..." << std::endl; + } + else QMessageBox::information(this, "Need to open image","You must open an image first."); +} + +//==================================================================== +void vvMainWindow::WarpImage() +{ + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + if (!mSlicerManagers[index]->GetVF().IsNull()) + { + bool ok; + int ref = QInputDialog::getInteger(this,"Chose reference phase","Reference phase",0,0,\ + mSlicerManagers[index]->GetImage()->GetVTKImages().size()-1,1,&ok); + if (ok) + { + WarpImage(mSlicerManagers[index],ref); + } + } + else + QMessageBox::warning(this,tr("No vector field"),tr("Sorry, can't warp without a vector field")); +} + +//==================================================================== +void vvMainWindow::WarpImage(vvSlicerManager* selected_slicer,int reference_phase) +{ + if (!selected_slicer->GetVF().IsNull()) + { + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + QFileInfo info(selected_slicer->GetFileName().c_str()); + vvImageWarp warp(selected_slicer->GetImage(),selected_slicer->GetVF(), + reference_phase,this); + if (warp.ComputeWarpedImage()) + { + AddImage(warp.GetWarpedImage(),info.path().toStdString()+"/"+info.completeBaseName().toStdString()+"_warped.mhd"); + AddImage(warp.GetDiffImage() ,info.path().toStdString()+"/"+info.completeBaseName().toStdString()+"_diff.mhd"); + AddImage(warp.GetJacobianImage() ,info.path().toStdString()+"/"+info.completeBaseName().toStdString()+"_jacobian.mhd"); + QApplication::restoreOverrideCursor(); + } + else + { + QApplication::restoreOverrideCursor(); + QMessageBox::warning(this,tr("Different spacings"),tr("The vector field and image spacings must be the same in order to warp.")); + } + } + else + QMessageBox::warning(this,tr("No vector field"),tr("Sorry, can't warp without a vector field.")); +} + +//==================================================================== +vvMainWindow::~vvMainWindow() { + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) + { + if (mSlicerManagers[i] != NULL) + delete mSlicerManagers[i]; + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::MergeImages() { + QString Extensions = "Images ( *.bmp *.png *.jpeg *.jpg *.tif *.mhd *.hdr *.vox)"; + Extensions += ";;All Files (*)"; + QStringList files = QFileDialog::getOpenFileNames(this,tr("Merge Images"),mInputPathName,Extensions); + if (files.isEmpty()) + return; + mInputPathName = itksys::SystemTools::GetFilenamePath(files[0].toStdString()).c_str(); + std::vector vector; + + unsigned int currentDim = 0; + std::vector currentSpacing; + std::vector currentSize; + std::vector currentOrigin; + + for (int i = 0; i < files.size(); i++) + { + itk::ImageIOBase::Pointer reader = itk::ImageIOFactory::CreateImageIO( + files[i].toStdString().c_str(), itk::ImageIOFactory::ReadMode); + reader->SetFileName(files[i].toStdString().c_str()); + reader->ReadImageInformation(); + if (reader) NOViewWidget->hide(); + NEViewWidget->hide(); + SOViewWidget->hide(); + SEViewWidget->hide(); + { + if (i == 0) + currentDim = reader->GetNumberOfDimensions(); + bool IsOk = true; + for (unsigned int j = 0;j < currentDim; j++) + { + if (i == 0) + { + if (j == 0) + { + currentSpacing.resize(currentDim); + currentSize.resize(currentDim); + currentOrigin.resize(currentDim); + } + currentOrigin[j] = reader->GetOrigin(j); + currentSpacing[j] = reader->GetSpacing(j); + currentSize[j] = reader->GetDimensions(j); + } + else if (currentDim != reader->GetNumberOfDimensions() + || currentSpacing[j] != reader->GetSpacing(j) + || currentSize[j] != (int)reader->GetDimensions(j) + || currentOrigin[j] != reader->GetOrigin(j)) + { + QString error = "Cannot read file (too different from others "; + error += files[i].toStdString().c_str(); + QMessageBox::information(this,tr("Reading problem"),error); + IsOk = false; + break; + } + } + if (IsOk) + vector.push_back(files[i].toStdString()); + } + } + if (vector.size() > 0) + LoadImages(vector, MERGED); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::MergeImagesWithTime() { + QString Extensions = "Images ( *.bmp *.png *.jpeg *.jpg *.tif *.mhd *.hdr *.vox)"; + Extensions += ";;All Files (*)"; + QStringList files = QFileDialog::getOpenFileNames(this,tr("Merge Images With Time"),mInputPathName,Extensions); + if (files.isEmpty()) + return; + mInputPathName = itksys::SystemTools::GetFilenamePath(files[0].toStdString()).c_str(); + std::vector vector; + + unsigned int currentDim = 0; + std::vector currentSpacing; + std::vector currentSize; + std::vector currentOrigin; + + for (int i = 0; i < files.size(); i++) + { + itk::ImageIOBase::Pointer reader = itk::ImageIOFactory::CreateImageIO( + files[i].toStdString().c_str(), itk::ImageIOFactory::ReadMode); + if (reader) + { + reader->SetFileName(files[i].toStdString().c_str()); + reader->ReadImageInformation(); + if (i == 0) + currentDim = reader->GetNumberOfDimensions(); + bool IsOk = true; + for (unsigned int j = 0;j < currentDim; j++) + { + if (i == 0) + { + if (j == 0) + { + currentSpacing.resize(currentDim); + currentSize.resize(currentDim); + currentOrigin.resize(currentDim); + } + currentOrigin[j] = reader->GetOrigin(j); + currentSpacing[j] = reader->GetSpacing(j); + currentSize[j] = reader->GetDimensions(j); + } + else if (currentDim != reader->GetNumberOfDimensions() + || currentSpacing[j] != reader->GetSpacing(j) + || currentSize[j] != (int)reader->GetDimensions(j) + || currentOrigin[j] != reader->GetOrigin(j)) + { + QString error = "Cannot read file (too different from others "; + error += files[i].toStdString().c_str(); + QMessageBox::information(this,tr("Reading problem"),error); + IsOk = false; + break; + } + } + if (IsOk) + vector.push_back(files[i].toStdString()); + } + else + { + QString error = "Cannot read file info for "; + error += files[i].toStdString().c_str(); + error += "\n"; + error += "Maybe you're trying to open an image in an unsupported format?\n"; + QMessageBox::information(this,tr("Reading problem"),error); + } + } + sort(vector.begin(),vector.end()); + if (vector.size() > 1) + LoadImages(vector, MERGEDWITHTIME); + else + QMessageBox::warning(this,tr("Reading problem"),"You need to select at least two images to merge images with time.\nIf you only want to open one image, please use the \"Open Image\" function."); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::OpenDicom() { + std::vector files; + +#ifdef CLITK_VV_USE_BDCM + bool r = bdcm::OpenDicomFilesSelectorDialog(files, + "DicomFilesSelectorDialog test", + 0,0,800,800,1); + + if (r) { + std::cout << "$$$$ main : user clicked 'OK' $$$$"<::iterator i; + for (i=files.begin();i!=files.end();++i) { + std::cout << *i << std::endl; + } + std::cout << "$$$$ "<exec() == QDialog::Accepted) { + files = *(dicomSeriesSelector->GetFilenames()); + LoadImages(files,DICOM); + } +#endif + +} +//==================================================================== + +//==================================================================== +void vvMainWindow::OpenImages() { + QString Extensions = "Images ( *.bmp *.png *.jpeg *.jpg *.tif *.mhd *.hdr *.vox)"; + Extensions += ";;All Files (*)"; + + QStringList files = QFileDialog::getOpenFileNames(this,tr("Load Images"),mInputPathName,Extensions); + if (files.isEmpty()) + return; + mInputPathName = itksys::SystemTools::GetFilenamePath(files[0].toStdString()).c_str(); + std::vector vector; + for (int i = 0; i < files.size(); i++) + vector.push_back(files[i].toStdString()); + LoadImages(vector, IMAGE); +} +//==================================================================== +void vvMainWindow::OpenRecentImage() +{ + QAction * caller = qobject_cast(sender()); + std::vector images; + images.push_back(caller->text().toStdString()); + mInputPathName = itksys::SystemTools::GetFilenamePath(images[0]).c_str(); + LoadImages(images,IMAGE); +} + +//==================================================================== +void vvMainWindow::OpenImageWithTime() { + QString Extensions = "Images ( *.bmp *.png *.jpeg *.jpg *.tif *.mhd *.hdr *.vox)"; + Extensions += ";;All Files (*)"; + + QStringList files = QFileDialog::getOpenFileNames(this,tr("Load Images With Time"),mInputPathName,Extensions); + if (files.isEmpty()) + return; + mInputPathName = itksys::SystemTools::GetFilenamePath(files[0].toStdString()).c_str(); + std::vector vector; + for (int i = 0; i < files.size(); i++) + { + vector.push_back(files[i].toStdString()); + } + LoadImages(vector, IMAGEWITHTIME); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::LoadImages(std::vector files, LoadedImageType filetype) { + //Separate the way to open images and dicoms + int fileSize; + if (filetype == IMAGE || filetype == IMAGEWITHTIME) + fileSize = files.size(); + else + fileSize = 1; + + //Only add to the list of recently opened files when a single file is opened, + //to avoid polluting the list of recently opened files + if (files.size() == 1) + { + QFileInfo finfo=tr(files[0].c_str()); + AddToRecentlyOpenedImages(finfo.absoluteFilePath().toStdString()); + } + //init the progress events + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + vvProgressDialog progress("Opening " + files[0],fileSize>1); + qApp->processEvents(); + + int numberofsuccesulreads=0; + //open images as 1 or multiples + for (int i = 0; i < fileSize; i++) { + + progress.Update("Opening " + files[i]); + progress.SetProgress(i,fileSize); + qApp->processEvents(); + + //read the image and put it in mSlicerManagers + vvSlicerManager* imageManager = new vvSlicerManager(4); + qApp->processEvents(); + + bool SetImageSucceed=false; + + if (filetype == IMAGE || filetype == IMAGEWITHTIME) + SetImageSucceed = imageManager->SetImage(files[i],filetype); + else + { + SetImageSucceed = imageManager->SetImages(files,filetype); + } + if (SetImageSucceed == false) + { + QApplication::restoreOverrideCursor(); + QString error = "Cannot open file \n"; + error += imageManager->GetLastError().c_str(); + QMessageBox::information(this,tr("Reading problem"),error); + delete imageManager; + } + else + { + mSlicerManagers.push_back(imageManager); + + //create an item in the tree with good settings + QTreeWidgetItem *item = new QTreeWidgetItem(); + item->setData(0,Qt::UserRole,files[i].c_str()); + QFileInfo fileinfo(imageManager->GetFileName().c_str()); //Do not show the path + item->setData(COLUMN_IMAGE_NAME,Qt::DisplayRole,fileinfo.fileName()); + qApp->processEvents(); + + //Create the buttons for reload and close + qApp->processEvents(); + QTreePushButton* cButton = new QTreePushButton; + cButton->setItem(item); + cButton->setColumn(COLUMN_CLOSE_IMAGE); + cButton->setToolTip(tr("close image")); + cButton->setIcon(QIcon(QString::fromUtf8(":/new/prefix1/icons/exit.png"))); + connect(cButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(CloseImage(QTreeWidgetItem*, int))); + + QTreePushButton* rButton = new QTreePushButton; + rButton->setItem(item); + rButton->setColumn(COLUMN_RELOAD_IMAGE); + rButton->setToolTip(tr("reload image")); + rButton->setIcon(QIcon(QString::fromUtf8(":/new/prefix1/icons/rotateright.png"))); + connect(rButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(ReloadImage(QTreeWidgetItem*, int))); + + DataTree->addTopLevelItem(item); + DataTree->setItemWidget(item, COLUMN_CLOSE_IMAGE, cButton); + DataTree->setItemWidget(item, COLUMN_RELOAD_IMAGE, rButton); + + //set the id of the image + QString id = files[i].c_str() + QString::number(mSlicerManagers.size()-1); + item->setData(COLUMN_IMAGE_NAME,Qt::UserRole,id.toStdString().c_str()); + mSlicerManagers.back()->SetId(id.toStdString()); + + linkPanel->addImage(imageManager->GetFileName(), id.toStdString()); + + connect(mSlicerManagers.back(),SIGNAL(currentImageChanged(std::string)), + this,SLOT(CurrentImageChanged(std::string))); + connect(mSlicerManagers.back(),SIGNAL( + UpdatePosition(int, double, double, double, double, double, double, double)),this, + SLOT(MousePositionChanged(int,double, double, double, double, double, double, double))); + connect(mSlicerManagers.back(),SIGNAL(UpdateVector(int, double, double, double, double)), + this, SLOT(VectorChanged(int,double,double,double, double))); + connect(mSlicerManagers.back(),SIGNAL(UpdateOverlay(int, double, double)), + this, SLOT(OverlayChanged(int,double,double))); + connect(mSlicerManagers.back(),SIGNAL(UpdateFusion(int, double)), + this, SLOT(FusionChanged(int,double))); + connect(mSlicerManagers.back(),SIGNAL(UpdateWindows(int, int, int)), + this,SLOT(WindowsChanged(int, int, int))); + connect(mSlicerManagers.back(),SIGNAL(WindowLevelChanged(double, double,int, int)), + this,SLOT(WindowLevelChanged(double, double, int, int))); + connect(mSlicerManagers.back(),SIGNAL(UpdateSlice(int,int)), + this,SLOT(UpdateSlice(int,int))); + connect(mSlicerManagers.back(),SIGNAL(UpdateTSlice(int, int)), + this,SLOT(UpdateTSlice(int, int))); + connect(mSlicerManagers.back(),SIGNAL(UpdateSliceRange(int,int,int,int,int)), + this,SLOT(UpdateSliceRange(int,int,int,int,int))); + connect(mSlicerManagers.back(),SIGNAL(UpdateLinkManager(std::string,int,double,double,double,int)), + this,SLOT(UpdateLinkManager(std::string,int,double,double,double,int))); + connect(mSlicerManagers.back(),SIGNAL(LandmarkAdded()),landmarksPanel,SLOT(AddPoint())); + InitSlicers(); + numberofsuccesulreads++; + } + } + if (numberofsuccesulreads) + { + NOViewWidget->show(); + NEViewWidget->show(); + SOViewWidget->show(); + SEViewWidget->show(); + UpdateTree(); + InitDisplay(); + ShowLastImage(); + } + QApplication::restoreOverrideCursor(); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::UpdateTree() { + DataTree->resizeColumnToContents(COLUMN_TREE); + DataTree->resizeColumnToContents(COLUMN_UL_VIEW); + DataTree->resizeColumnToContents(COLUMN_UR_VIEW); + DataTree->resizeColumnToContents(COLUMN_DL_VIEW); + DataTree->resizeColumnToContents(COLUMN_DR_VIEW); + DataTree->resizeColumnToContents(COLUMN_IMAGE_NAME); + DataTree->resizeColumnToContents(COLUMN_CLOSE_IMAGE); + DataTree->resizeColumnToContents(COLUMN_RELOAD_IMAGE); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::CurrentImageChanged(std::string id) { + int selected = 0; + for (int i = 0; i < DataTree->topLevelItemCount(); i++) + { + if (DataTree->topLevelItem(i)->data(COLUMN_IMAGE_NAME,Qt::UserRole).toString().toStdString() == id) + { + selected = i; + } + else + { + DataTree->topLevelItem(i)->setSelected(0); + } + for (int child = 0; child < DataTree->topLevelItem(i)->childCount();child++) + DataTree->topLevelItem(i)->child(child)->setSelected(0); + + } + DataTree->topLevelItem(selected)->setSelected(1); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::ImageInfoChanged() { + contextActions[7]->setEnabled(1); + contextActions[6]->setEnabled(1); + actionSave_As->setEnabled(1); + actionAdd_VF_to_current_Image->setEnabled(1); + actionAdd_fusion_image->setEnabled(1); + actionNorth_East_Window->setEnabled(1); + actionNorth_West_Window->setEnabled(1); + actionSouth_East_Window->setEnabled(1); + actionSouth_West_Window->setEnabled(1); + inverseButton->setEnabled(1); + + goToCursorPushButton->setEnabled(1); + + if (DataTree->selectedItems().size()) { + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + + colorMapComboBox->setEnabled(1); + for (int i = 0; i < DataTree->topLevelItem(index)->childCount();i++) + { + if (DataTree->topLevelItem(index)->child(i)->data(1,Qt::UserRole).toString() == "overlay" || + DataTree->topLevelItem(index)->child(i)->data(1,Qt::UserRole).toString() == "fusion") + { + colorMapComboBox->setEnabled(0); + break; + } + } + + std::vector origin; + std::vector inputSpacing; + std::vector inputSize; + std::vector sizeMM; + int dimension=0; + QString pixelType; + QString inputSizeInBytes; + QString image = DataTree->selectedItems()[0]->data(COLUMN_IMAGE_NAME,Qt::DisplayRole).toString(); + + if (mSlicerManagers[index]->GetSlicer(0)->GetImage()->GetVTKImages().size() > 1 || playMode == 1) + { + playButton->setEnabled(1); + frameRateLabel->setEnabled(1); + frameRateSpinBox->setEnabled(1); + } + else + { + playButton->setEnabled(0); + frameRateLabel->setEnabled(0); + frameRateSpinBox->setEnabled(0); + } + + //read image header + int NPixel = 1; + + if (DataTree->topLevelItem(index) == DataTree->selectedItems()[0]) + { + vvImage::Pointer imageSelected = mSlicerManagers[index]->GetSlicer(0)->GetImage(); + dimension = imageSelected->GetNumberOfDimensions(); + origin.resize(dimension); + inputSpacing.resize(dimension); + inputSize.resize(dimension); + sizeMM.resize(dimension); + pixelType = mSlicerManagers[index]->GetImage()->GetScalarTypeAsString().c_str(); + for (int i = 0;i < dimension;i++) + { + origin[i] = imageSelected->GetOrigin()[i]; + inputSpacing[i] = imageSelected->GetSpacing()[i]; + inputSize[i] = imageSelected->GetSize()[i]; + sizeMM[i] = inputSize[i]*inputSpacing[i]; + NPixel *= inputSize[i]; + } + inputSizeInBytes = GetSizeInBytes(imageSelected->GetActualMemorySize()*1000); + } + else if (DataTree->selectedItems()[0]->data(1,Qt::UserRole).toString() == "vector") + { + vvImage::Pointer imageSelected = mSlicerManagers[index]->GetSlicer(0)->GetVF(); + dimension = imageSelected->GetNumberOfDimensions(); + origin.resize(dimension); + inputSpacing.resize(dimension); + inputSize.resize(dimension); + sizeMM.resize(dimension); + pixelType = mSlicerManagers[index]->GetVF()->GetScalarTypeAsString().c_str(); + for (int i = 0;i < dimension;i++) + { + origin[i] = imageSelected->GetOrigin()[i]; + inputSpacing[i] = imageSelected->GetSpacing()[i]; + inputSize[i] = imageSelected->GetSize()[i]; + sizeMM[i] = inputSize[i]*inputSpacing[i]; + NPixel *= inputSize[i]; + } + inputSizeInBytes = GetSizeInBytes(imageSelected->GetActualMemorySize()*1000); + } + else if (DataTree->selectedItems()[0]->data(1,Qt::UserRole).toString() == "overlay") + { + vvImage::Pointer imageSelected = mSlicerManagers[index]->GetSlicer(0)->GetOverlay(); + dimension = imageSelected->GetNumberOfDimensions(); + origin.resize(dimension); + inputSpacing.resize(dimension); + inputSize.resize(dimension); + sizeMM.resize(dimension); + pixelType = mSlicerManagers[index]->GetImage()->GetScalarTypeAsString().c_str(); + for (int i = 0;i < dimension;i++) + { + origin[i] = imageSelected->GetOrigin()[i]; + inputSpacing[i] = imageSelected->GetSpacing()[i]; + inputSize[i] = imageSelected->GetSize()[i]; + sizeMM[i] = inputSize[i]*inputSpacing[i]; + NPixel *= inputSize[i]; + } + inputSizeInBytes = GetSizeInBytes(imageSelected->GetActualMemorySize()*1000); + } + else if (DataTree->selectedItems()[0]->data(1,Qt::UserRole).toString() == "fusion") + { + vvImage::Pointer imageSelected = mSlicerManagers[index]->GetSlicer(0)->GetFusion(); + dimension = imageSelected->GetNumberOfDimensions(); + origin.resize(dimension); + inputSpacing.resize(dimension); + inputSize.resize(dimension); + sizeMM.resize(dimension); + pixelType = mSlicerManagers[index]->GetImage()->GetScalarTypeAsString().c_str(); + for (int i = 0;i < dimension;i++) + { + origin[i] = imageSelected->GetOrigin()[i]; + inputSpacing[i] = imageSelected->GetSpacing()[i]; + inputSize[i] = imageSelected->GetSize()[i]; + sizeMM[i] = inputSize[i]*inputSpacing[i]; + NPixel *= inputSize[i]; + } + inputSizeInBytes = GetSizeInBytes(imageSelected->GetActualMemorySize()*1000); + } + + QString dim = QString::number(dimension) + " ("; + dim += pixelType + ")"; + + infoPanel->setFileName(image); + infoPanel->setDimension(dim); + infoPanel->setSizePixel(GetVectorIntAsString(inputSize)); + infoPanel->setSizeMM(GetVectorDoubleAsString(sizeMM)); + infoPanel->setOrigin(GetVectorDoubleAsString(origin)); + infoPanel->setSpacing(GetVectorDoubleAsString(inputSpacing)); + infoPanel->setNPixel(QString::number(NPixel)+" ("+inputSizeInBytes+")"); + + landmarksPanel->SetCurrentLandmarks(mSlicerManagers[index]->GetLandmarks(), + mSlicerManagers[index]->GetSlicer(0)->GetImage()->GetVTKImages().size()); + landmarksPanel->SetCurrentPath(mInputPathName.toStdString()); + landmarksPanel->SetCurrentImage(mSlicerManagers[index]->GetFileName().c_str()); + + overlayPanel->getCurrentImageName(mSlicerManagers[index]->GetFileName().c_str()); + for (int i = 0; i < 4;i++) + { + if (DataTree->selectedItems()[0]->data(i+1,Qt::CheckStateRole).toInt() > 0 || i == 3) + { + mSlicerManagers[index]->UpdateInfoOnCursorPosition(i); + break; + } + } + windowSpinBox->setValue(mSlicerManagers[index]->GetColorWindow()); + levelSpinBox->setValue(mSlicerManagers[index]->GetColorLevel()); + DD(mSlicerManagers[index]->GetColorMap()); + DD(mSlicerManagers[index]->GetPreset()); + presetComboBox->setCurrentIndex(mSlicerManagers[index]->GetPreset()); + colorMapComboBox->setCurrentIndex(mSlicerManagers[index]->GetColorMap()); + + if (mSlicerManagers[index]->GetSlicer(0)->GetVF()) + { + overlayPanel->getVFName(mSlicerManagers[index]->GetVFName().c_str()); + overlayPanel->getVFProperty(mSlicerManagers[index]->GetSlicer(0)->GetVFSubSampling(), + mSlicerManagers[index]->GetSlicer(0)->GetVFScale(), + mSlicerManagers[index]->GetSlicer(0)->GetVFLog()); + } + else + { + overlayPanel->getVFName(mSlicerManagers[index]->GetVFName().c_str()); + overlayPanel->getVFProperty(-1,-1,-1); + } + if (mSlicerManagers[index]->GetSlicer(0)->GetOverlay()) + { + overlayPanel->getOverlayName(mSlicerManagers[index]->GetOverlayName().c_str()); + overlayPanel->getOverlayProperty(mSlicerManagers[index]->GetOverlayColor()); + } + else + { + overlayPanel->getOverlayName(mSlicerManagers[index]->GetOverlayName().c_str()); + overlayPanel->getOverlayProperty(-1); + } + if (mSlicerManagers[index]->GetSlicer(0)->GetFusion()) + { + overlayPanel->getFusionName(mSlicerManagers[index]->GetFusionName().c_str()); + overlayPanel->getFusionProperty(mSlicerManagers[index]->GetFusionOpacity(), + mSlicerManagers[index]->GetFusionColorMap(), + mSlicerManagers[index]->GetFusionWindow(), + mSlicerManagers[index]->GetFusionLevel()); + } + else + { + overlayPanel->getFusionName(mSlicerManagers[index]->GetFusionName().c_str()); + overlayPanel->getFusionProperty(-1, -1,-1,-1); + } + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::ShowDocumentation() { + documentation->show(); +} +//==================================================================== +void vvMainWindow::ShowHelpDialog() { + help_dialog->show(); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::ChangeViewMode() { + QListIterator it0(splitter_3->sizes()); + QListIterator it1(splitter_3->sizes()); + int max0 = 0; + int max1 = 1; + while (it0.hasNext()) + { + max0 += it0.next(); + } + while (it1.hasNext()) + { + max1 += it1.next(); + } + QList size0; + QList size1; + if (viewMode == 1) + { + viewMode = 0; + size0.push_back(max0); + size0.push_back(0); + size1.push_back(max1); + size1.push_back(0); + splitter_3->setSizes(size0); + OSplitter->setSizes(size1); + DataTree->setColumnHidden(2,1); + DataTree->setColumnHidden(3,1); + DataTree->setColumnHidden(4,1); + } + else + { + viewMode = 1; + size0.push_back(int(max0/2)); + size0.push_back(int(max0/2)); + size1.push_back(int(max1/2)); + size1.push_back(int(max1/2)); + splitter_3->setSizes(size0); + OSplitter->setSizes(size1); + DataTree->setColumnHidden(2,0); + DataTree->setColumnHidden(3,0); + DataTree->setColumnHidden(4,0); + } +} +//==================================================================== + +//==================================================================== +QString vvMainWindow::GetSizeInBytes(unsigned long size) { + QString result = "";// QString::number(size); + //result += " bytes ("; + if (size > 1000000000) + { + size /= 1000000000; + result += QString::number(size); + result += "Gb";//)"; + } + else if (size > 1000000) + { + size /= 1000000; + result += QString::number(size); + result += "Mb";//)"; + } + else if (size > 1000) + { + size /= 1000; + result += QString::number(size); + result += "kb";//)"; + } + return result; +} +//==================================================================== + +//==================================================================== +QString vvMainWindow::GetVectorDoubleAsString(std::vector vectorDouble) { + QString result; + for (unsigned int i= 0; i < vectorDouble.size(); i++) + { + if (i != 0) + result += " "; + result += QString::number(vectorDouble[i]); + } + return result; +} +//==================================================================== + +//==================================================================== +QString vvMainWindow::GetVectorIntAsString(std::vector vectorInt) { + QString result; + for (unsigned int i= 0; i < vectorInt.size(); i++) + { + if (i != 0) + result += " "; + result += QString::number(vectorInt[i]); + } + return result; +} +//==================================================================== + +//==================================================================== +int vvMainWindow::GetSlicerIndexFromItem(QTreeWidgetItem* item) { + QString id = item->data(COLUMN_IMAGE_NAME,Qt::UserRole).toString(); + for (int i = 0; i < DataTree->topLevelItemCount(); i++) + { + if (DataTree->topLevelItem(i)->data(COLUMN_IMAGE_NAME,Qt::UserRole).toString() == id) + return i; + } + return -1; +} +//==================================================================== + +//==================================================================== +void vvMainWindow::DisplayChanged(QTreeWidgetItem *clicked_item, int column) { + int index = GetSlicerIndexFromItem(clicked_item); + if ( column >= COLUMN_CLOSE_IMAGE or column <= 0) + return; + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) + { + QTreeWidgetItem* current_row=DataTree->topLevelItem(i); + if (DataTree->topLevelItem(index) == current_row) + { + vvSlicer* clicked_slicer=mSlicerManagers[i]->GetSlicer(column-1); + if (current_row == clicked_item) + { + //If we just activated a slicer + if (current_row->data(column,Qt::CheckStateRole).toInt() > 0) + { + mSlicerManagers[i]->UpdateSlicer(column-1,clicked_item->data(column,Qt::CheckStateRole).toInt()); + mSlicerManagers[i]->UpdateInfoOnCursorPosition(column-1); + DisplaySliders(i,column-1); + std::map overlay_counts; + for (int child = 0; child < current_row->childCount(); child++) + { + std::string overlay_type = + current_row->child(child)->data(1,Qt::UserRole).toString().toStdString(); + overlay_counts[overlay_type]++; + current_row->child(child)->setData(column,Qt::CheckStateRole, + current_row->data(column,Qt::CheckStateRole)); + clicked_slicer->SetActorVisibility(overlay_type,overlay_counts[overlay_type]-1,true); + } + } + else //We don't allow simply desactivating a slicer + { + clicked_item->setData(column,Qt::CheckStateRole,2); + return; + } + } + //if we clicked on the vector(or overlay) and not the image + else + { + if (clicked_item->data(column,Qt::CheckStateRole).toInt()) + { + current_row->setData(column,Qt::CheckStateRole,2); + mSlicerManagers[i]->UpdateSlicer(column-1,2); + mSlicerManagers[i]->UpdateInfoOnCursorPosition(column-1); + DisplaySliders(i,column-1); + } + int vis = clicked_item->data(column,Qt::CheckStateRole).toInt(); + std::string overlay_type = clicked_item->data(1,Qt::UserRole).toString().toStdString(); + int overlay_index=0; + for (int child = 0; child < current_row->childCount(); child++) + { + if (current_row->child(child)->data(1,Qt::UserRole).toString().toStdString() == overlay_type) + overlay_index++; + if (current_row->child(child) == clicked_item) break; + } + clicked_slicer->SetActorVisibility( + clicked_item->data(1,Qt::UserRole).toString().toStdString(), overlay_index-1,vis); + } + } + else if (current_row->data(column,Qt::CheckStateRole).toInt() > 0) + { + current_row->setData(column,Qt::CheckStateRole,0); + mSlicerManagers[i]->UpdateSlicer(column-1,0); + std::map overlay_counts; + for (int child = 0; child < current_row->childCount(); child++) + { + std::string overlay_type = + current_row->child(child)->data(1,Qt::UserRole).toString().toStdString(); + overlay_counts[overlay_type]++; + current_row->child(child)->setData(column,Qt::CheckStateRole,0); + vvSlicer * current_slicer=mSlicerManagers[i]->GetSlicer(column-1); + current_slicer->SetActorVisibility(overlay_type,overlay_counts[overlay_type]-1,false); + } + } + //mSlicerManagers[i]->SetColorMap(-1); + } + mSlicerManagers[index]->GetSlicer(column-1)->Render(); +} +//==================================================================== + +void vvMainWindow::InitSlicers() +{ + if (mSlicerManagers.size()) + { + mSlicerManagers.back()->GenerateDefaultLookupTable(); + + mSlicerManagers.back()->SetSlicerWindow(0,NOViewWidget->GetRenderWindow()); + mSlicerManagers.back()->SetSlicerWindow(1,NEViewWidget->GetRenderWindow()); + mSlicerManagers.back()->SetSlicerWindow(2,SOViewWidget->GetRenderWindow()); + mSlicerManagers.back()->SetSlicerWindow(3,SEViewWidget->GetRenderWindow()); + } +} + +//==================================================================== +void vvMainWindow::InitDisplay() { + if (mSlicerManagers.size()) + { + //BE CAREFUL : this is absolutely necessary to set the interactor style + //in order to have the same style instanciation for all SlicerManagers in + // a same window + for (int j = 0; j < 4; j++) + { + vvInteractorStyleNavigator* style = vvInteractorStyleNavigator::New(); + style->SetAutoAdjustCameraClippingRange(1); + bool AlreadySelected = false; + for (int i = 0; i < DataTree->topLevelItemCount(); i++) + { + mSlicerManagers[i]->SetInteractorStyleNavigator(j,style); + + //select the image only if previous are not selected + if (DataTree->topLevelItem(i)->data(j+1,Qt::CheckStateRole).toInt() > 1) + { + mSlicerManagers[i]->UpdateSlicer(j,1); + AlreadySelected = true; + } + else if (i == DataTree->topLevelItemCount()-1 && !AlreadySelected) + { + if (DataTree->selectedItems().size() == 0) + DataTree->topLevelItem(i)->setSelected(1); + DataTree->topLevelItem(i)->setData(j+1,Qt::CheckStateRole,2); + mSlicerManagers[i]->UpdateSlicer(j,1); + DisplaySliders(i,j); + } + else + { + DataTree->topLevelItem(i)->setData(j+1,Qt::CheckStateRole,0); + mSlicerManagers[i]->UpdateSlicer(j,0); + } + } + style->Delete(); + } + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::DisplaySliders(int slicer, int window) { + int range[2]; + mSlicerManagers[slicer]->GetSlicer(window)->GetSliceRange(range); + int position = mSlicerManagers[slicer]->GetSlicer(window)->GetSlice(); + + int tRange[2]; + tRange[0] = 0; + tRange[1] = mSlicerManagers[slicer]->GetSlicer(window)->GetTMax(); + int tPosition = mSlicerManagers[slicer]->GetSlicer(window)->GetTSlice(); + bool showHorizontal = false; + bool showVertical = false; + if (mSlicerManagers[slicer]->GetSlicer(window)->GetImage()->GetNumberOfDimensions() > 3 + || (mSlicerManagers[slicer]->GetSlicer(window)->GetImage()->GetNumberOfDimensions() > 2 + && mSlicerManagers[slicer]->GetType() != IMAGEWITHTIME + && mSlicerManagers[slicer]->GetType() != MERGEDWITHTIME)) + showVertical = true; + if (mSlicerManagers[slicer]->GetSlicer(window)->GetImage()->GetNumberOfDimensions() > 3 + || mSlicerManagers[slicer]->GetType() == IMAGEWITHTIME + || mSlicerManagers[slicer]->GetType() == MERGEDWITHTIME) + showHorizontal = true; + + if (showVertical) + verticalSliders[window]->show(); + else + verticalSliders[window]->hide(); + verticalSliders[window]->setRange(range[0],range[1]); + verticalSliders[window]->setValue(position); + + if (showHorizontal) + horizontalSliders[window]->show(); + else + horizontalSliders[window]->hide(); + horizontalSliders[window]->setRange(tRange[0],tRange[1]); + horizontalSliders[window]->setValue(tPosition); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::CloseImage(QTreeWidgetItem* item, int column) { + int index = GetSlicerIndexFromItem(item); + + if (DataTree->topLevelItem(index) != item) + { + QString warning = "Do you really want to close the overlay : "; + warning += item->data(COLUMN_IMAGE_NAME,Qt::DisplayRole).toString(); + QMessageBox msgBox(QMessageBox::Warning, tr("Close Overlay"), + warning, 0, this); + msgBox.addButton(tr("Close"), QMessageBox::AcceptRole); + msgBox.addButton(tr("Cancel"), QMessageBox::RejectRole); + if (msgBox.exec() == QMessageBox::AcceptRole) + { + std::string overlay_type=item->data(1,Qt::UserRole).toString().toStdString(); + int overlay_index=0; + for (int child = 0; child < DataTree->topLevelItem(index)->childCount(); child++) + { + if (DataTree->topLevelItem(index)->\ + child(child)->data(1,Qt::UserRole).toString().toStdString() == overlay_type) + overlay_index++; + if (DataTree->topLevelItem(index)->child(child) == item) break; + } + mSlicerManagers[index]->RemoveActor(overlay_type, overlay_index-1); + mSlicerManagers[index]->SetColorMap(0); + DataTree->topLevelItem(index)->takeChild(DataTree->topLevelItem(index)->indexOfChild(item)); + mSlicerManagers[index]->Render(); + } + } + else if (DataTree->topLevelItemCount() <= 1) + { + QString warning = "Do you really want to close the image : "; + warning += item->data(COLUMN_IMAGE_NAME,Qt::DisplayRole).toString(); + warning += "\nThis is the last image, you're about to close vv !!!"; + QMessageBox msgBox(QMessageBox::Warning, tr("Close Image"), + warning, 0, this); + msgBox.addButton(tr("Close vv"), QMessageBox::AcceptRole); + msgBox.addButton(tr("Cancel"), QMessageBox::RejectRole); + if (msgBox.exec() == QMessageBox::AcceptRole) + { + this->close(); + } + } + else + { + QString warning = "Do you really want to close the image : "; + warning += item->data(COLUMN_IMAGE_NAME,Qt::DisplayRole).toString(); + QMessageBox msgBox(QMessageBox::Warning, tr("Close Image"), + warning, 0, this); + msgBox.addButton(tr("Close"), QMessageBox::AcceptRole); + msgBox.addButton(tr("Cancel"), QMessageBox::RejectRole); + if (msgBox.exec() == QMessageBox::AcceptRole) + { + std::vector::iterator Manageriter = mSlicerManagers.begin(); + DataTree->takeTopLevelItem(index); + for (int i = 0; i < index; i++) + { + Manageriter++; + } + linkPanel->removeImage(index); + mSlicerManagers[index]->RemoveActors(); + delete mSlicerManagers[index]; + mSlicerManagers.erase(Manageriter); + InitDisplay(); + } + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::ReloadImage(QTreeWidgetItem* item, int column) { + int index = GetSlicerIndexFromItem(item); + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + if (item->data(1,Qt::UserRole).toString() == "vector") + mSlicerManagers[index]->ReloadVF(); + else + mSlicerManagers[index]->Reload(); + QApplication::restoreOverrideCursor(); +} +//==================================================================== + +void vvMainWindow::CropImage() +{ + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + vvCropDialog crop(mSlicerManagers,index); + if(crop.exec()) + AddImage(crop.GetOutput(),"cropped.mhd"); +} + +//==================================================================== +void vvMainWindow::SplitImage() { + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + int dim = mSlicerManagers[index]->GetDimension(); + QString warning = "Do you really want to split the "; + warning += QString::number(dim) + "D image "; + warning += DataTree->selectedItems()[0]->data(COLUMN_IMAGE_NAME,Qt::DisplayRole).toString() + " into "; + warning += QString::number(mSlicerManagers[index]->GetSlicer(0)->GetImage()->GetSize()[dim-1]) + " "; + warning += QString::number(dim-1) + "D images."; + QMessageBox msgBox(QMessageBox::Warning, tr("Split Image"), + warning, 0, this); + msgBox.addButton(tr("Split"), QMessageBox::AcceptRole); + msgBox.addButton(tr("Cancel"), QMessageBox::RejectRole); + if (msgBox.exec() == QMessageBox::AcceptRole) + { + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + if (dim > 2) + { + std::string filename = DataTree->selectedItems()[0]->data(0,Qt::UserRole).toString().toStdString(); + int numberOfSlice = mSlicerManagers[index]->GetSlicer(0)->GetImage()->GetSize()[dim-1]; + std::string path = itksys::SystemTools::GetFilenamePath( + filename); + path += "/"; + path += DataTree->selectedItems()[0]->data(COLUMN_IMAGE_NAME,Qt::DisplayRole).toString().toStdString(); + path += "%03d"; + path += itksys::SystemTools::GetFilenameLastExtension( + filename).c_str(); + + typedef itk::NumericSeriesFileNames NameGeneratorType; + NameGeneratorType::Pointer nameGenerator = NameGeneratorType::New(); + nameGenerator->SetSeriesFormat(path.c_str()); + nameGenerator->SetStartIndex(0); + nameGenerator->SetEndIndex(numberOfSlice-1); + nameGenerator->SetIncrementIndex(1); + + for (int i = 0; i < numberOfSlice; i++) + { + vvSlicerManager* imageManager = new vvSlicerManager(4); + imageManager->SetExtractedImage(nameGenerator->GetFileNames()[i], + mSlicerManagers[index]->GetSlicer(0)->GetImage(), i); + mSlicerManagers.push_back(imageManager); + + //create an item in the tree with good settings + QTreeWidgetItem *item = new QTreeWidgetItem(); + item->setData(0,Qt::UserRole,nameGenerator->GetFileNames()[i].c_str()); + std::string fileI = itksys::SystemTools::GetFilenameWithoutLastExtension( + nameGenerator->GetFileNames()[i]).c_str(); + item->setData(COLUMN_IMAGE_NAME,Qt::DisplayRole,fileI.c_str()); + for (int j = 1; j <= 4; j++) + { + for (int i = 0; i < DataTree->topLevelItemCount(); i++) + { + DataTree->topLevelItem(i)->setData(j,Qt::CheckStateRole,0); + } + item->setData(j,Qt::CheckStateRole,2); + } + + //Create the buttons for reload and close + QTreePushButton* cButton = new QTreePushButton; + cButton->setItem(item); + cButton->setColumn(COLUMN_CLOSE_IMAGE); + cButton->setToolTip(tr("close image")); + cButton->setIcon(QIcon(QString::fromUtf8(":/new/prefix1/icons/exit.png"))); + connect(cButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(CloseImage(QTreeWidgetItem*, int))); + + QTreePushButton* rButton = new QTreePushButton; + rButton->setItem(item); + rButton->setColumn(COLUMN_RELOAD_IMAGE); + rButton->setToolTip(tr("reload image")); + rButton->setIcon(QIcon(QString::fromUtf8(":/new/prefix1/icons/rotateright.png"))); + rButton->setEnabled(false); + connect(rButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(ReloadImage(QTreeWidgetItem*, int))); + + DataTree->addTopLevelItem(item); + DataTree->setItemWidget(item, COLUMN_CLOSE_IMAGE, cButton); + DataTree->setItemWidget(item, COLUMN_RELOAD_IMAGE, rButton); + + //set the id of the image + QString id = nameGenerator->GetFileNames()[i].c_str() + QString::number(mSlicerManagers.size()-1); + item->setData(COLUMN_IMAGE_NAME,Qt::UserRole,id.toStdString().c_str()); + mSlicerManagers.back()->SetId(id.toStdString()); + linkPanel->addImage(fileI, id.toStdString()); + connect(mSlicerManagers.back(),SIGNAL(currentImageChanged(std::string)), + this,SLOT(CurrentImageChanged(std::string))); + connect(mSlicerManagers.back(),SIGNAL( + UpdatePosition(int, double, double, double, double, double, double, double)),this, + SLOT(MousePositionChanged(int,double, double, double, double, double, double, double))); + connect(mSlicerManagers.back(),SIGNAL(UpdateVector(int, double, double, double, double)), + this, SLOT(VectorChanged(int,double,double,double, double))); + connect(mSlicerManagers.back(),SIGNAL(UpdateOverlay(int, double, double)), + this, SLOT(OverlayChanged(int,double,double))); + connect(mSlicerManagers.back(),SIGNAL(UpdateFusion(int, double)), + this, SLOT(FusionChanged(int,double))); + connect(mSlicerManagers.back(),SIGNAL(UpdateWindows(int, int, int)), + this,SLOT(WindowsChanged(int, int, int))); + connect(mSlicerManagers.back(),SIGNAL(WindowLevelChanged(double, double,int, int)), + this,SLOT(WindowLevelChanged(double, double, int, int))); + connect(mSlicerManagers.back(),SIGNAL(UpdateSlice(int,int)), + this,SLOT(UpdateSlice(int,int))); + connect(mSlicerManagers.back(),SIGNAL(UpdateTSlice(int, int)), + this,SLOT(UpdateTSlice(int, int))); + connect(mSlicerManagers.back(),SIGNAL(UpdateSliceRange(int,int,int,int,int)), + this,SLOT(UpdateSliceRange(int,int,int,int,int))); + connect(mSlicerManagers.back(),SIGNAL(UpdateLinkManager(std::string,int,double,double,double,int)), + this,SLOT(UpdateLinkManager(std::string,int,double,double,double,int))); + connect(mSlicerManagers.back(),SIGNAL(LandmarkAdded()),landmarksPanel,SLOT(AddPoint())); + UpdateTree(); + qApp->processEvents(); + InitSlicers(); + InitDisplay(); + qApp->processEvents(); + } + QApplication::restoreOverrideCursor(); + } + else + { + QApplication::restoreOverrideCursor(); + QString error = "Cannot split file (dimensions must be greater than 2) "; + QMessageBox::information(this,tr("Splitting problem"),error); + } + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::MousePositionChanged(int visibility,double x, double y, double z, double X, double Y, double Z , double value) { + infoPanel->setCurrentInfo(visibility,x,y,z,X,Y,Z,value); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::VectorChanged(int visibility,double x, double y, double z, double value) { + overlayPanel->getCurrentVectorInfo(visibility,x,y,z,value); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::OverlayChanged(int visibility, double valueOver, double valueRef) { + overlayPanel->getCurrentOverlayInfo(visibility,valueOver, valueRef); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::FusionChanged(int visibility, double value) { + overlayPanel->getCurrentFusionInfo(visibility,value); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::WindowsChanged(int window, int view, int slice) { + infoPanel->setViews(window, view, slice); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::WindowLevelChanged(double window, double level,int preset,int colormap) { + windowSpinBox->setValue(window); + levelSpinBox->setValue(level); + colorMapComboBox->setCurrentIndex(colormap); + presetComboBox->setCurrentIndex(preset); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::WindowLevelEdited() { + presetComboBox->setCurrentIndex(6); + UpdateWindowLevel(); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::UpdateWindowLevel() { + if (DataTree->selectedItems().size()) + { + if (presetComboBox->currentIndex() == 7) //For ventilation + colorMapComboBox->setCurrentIndex(5); + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + mSlicerManagers[index]->SetColorWindow(windowSpinBox->value()); + mSlicerManagers[index]->SetColorLevel(levelSpinBox->value()); + mSlicerManagers[index]->SetPreset(presetComboBox->currentIndex()); + mSlicerManagers[index]->Render(); + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::UpdateColorMap() { + if (DataTree->selectedItems().size()) + { + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + mSlicerManagers[index]->SetColorMap(colorMapComboBox->currentIndex()); + mSlicerManagers[index]->Render(); + } +} +//==================================================================== +void vvMainWindow::SwitchWindowLevel() { + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + int window = mSlicerManagers[index]->GetColorWindow(); + presetComboBox->setCurrentIndex(6); + windowSpinBox->setValue(-window); + UpdateWindowLevel(); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::UpdateLinkManager(std::string id, int slicer, double x, double y, double z, int temps) { + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) + { + if (mSlicerManagers[i]->GetId() == id) + { + //mSlicerManagers[i]->SetTSlice(temps); + mSlicerManagers[i]->GetSlicer(slicer)->SetCurrentPosition(x,y,z,temps); + mSlicerManagers[i]->UpdateViews(0,slicer); + break; + } + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::ShowContextMenu(QPoint point) { + if (!DataTree->selectedItems().size()) + { + contextActions[1]->setEnabled(0); + contextActions[2]->setEnabled(0); + contextActions[3]->setEnabled(0); + contextActions[4]->setEnabled(0); + contextActions[5]->setEnabled(0); + contextActions[6]->setEnabled(0); + contextActions[7]->setEnabled(0); + } + else + { + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + contextActions[1]->setEnabled(1); + contextActions[2]->setEnabled( + DataTree->itemWidget(DataTree->selectedItems()[0], + COLUMN_RELOAD_IMAGE)->isEnabled()); + contextActions[3]->setEnabled(1); + contextActions[5]->setEnabled(1); + contextActions[6]->setEnabled(1); + contextActions[7]->setEnabled(1); + + if (mSlicerManagers[index]->GetDimension() < 3) + contextActions[4]->setEnabled(0); + else + contextActions[4]->setEnabled(1); + } + contextMenu.exec(QCursor::pos()); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::CloseImage() { + CloseImage(DataTree->selectedItems()[0],0); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::ReloadImage() { + ReloadImage(DataTree->selectedItems()[0],0); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::SelectOverlayImage() { + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + + //check if one overlay image is added + for (int child = 0; child < DataTree->topLevelItem(index)->childCount(); child++) + if (DataTree->topLevelItem(index)->child(child)->data(1,Qt::UserRole).toString() == "overlay") + { + QString error = "Cannot add more than one compared image\n"; + error += "Please remove first "; + error += DataTree->topLevelItem(index)->child(child)->data(COLUMN_IMAGE_NAME,Qt::DisplayRole).toString(); + QMessageBox::information(this,tr("Problem adding compared image !"),error); + return; + } + + QString Extensions = "Images ( *.bmp *.png *.jpeg *.jpg *.tif *.mhd *.hdr *.vox)"; + Extensions += ";;All Files (*)"; + QString file = QFileDialog::getOpenFileName(this,tr("Load Overlay image"),mInputPathName,Extensions); + if (!file.isEmpty()) + AddOverlayImage(index,file); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::AddOverlayImage(int index, QString file) { + mInputPathName = itksys::SystemTools::GetFilenamePath(file.toStdString()).c_str(); + itk::ImageIOBase::Pointer reader = itk::ImageIOFactory::CreateImageIO( + file.toStdString().c_str(), itk::ImageIOFactory::ReadMode); + reader->SetFileName(file.toStdString().c_str()); + reader->ReadImageInformation(); + std::string component = reader->GetComponentTypeAsString(reader->GetComponentType()); + int dimension = reader->GetNumberOfDimensions(); + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + vvProgressDialog progress("Opening " + file.toStdString()); + qApp->processEvents(); + + std::string filename = itksys::SystemTools::GetFilenameWithoutExtension(file.toStdString()).c_str(); + if (mSlicerManagers[index]->SetOverlay(file.toStdString(),dimension, component)) + { + //create an item in the tree with good settings + QTreeWidgetItem *item = new QTreeWidgetItem(); + item->setData(0,Qt::UserRole,file.toStdString().c_str()); + item->setData(1,Qt::UserRole,tr("overlay")); + item->setData(COLUMN_IMAGE_NAME,Qt::DisplayRole,filename.c_str()); + qApp->processEvents(); + + for (int j = 1; j <= 4; j++) + { + item->setData(j,Qt::CheckStateRole,DataTree->topLevelItem(index)->data(j,Qt::CheckStateRole)); + mSlicerManagers[index]->GetSlicer(j-1)->SetActorVisibility("overlay",0, + DataTree->topLevelItem(index)->data(j,Qt::CheckStateRole).toInt()); + } + + //Create the buttons for reload and close + qApp->processEvents(); + QTreePushButton* cButton = new QTreePushButton; + cButton->setItem(item); + cButton->setColumn(COLUMN_CLOSE_IMAGE); + cButton->setToolTip(tr("close image")); + cButton->setIcon(QIcon(QString::fromUtf8(":/new/prefix1/icons/exit.png"))); + connect(cButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(CloseImage(QTreeWidgetItem*, int))); + + QTreePushButton* rButton = new QTreePushButton; + rButton->setItem(item); + rButton->setColumn(COLUMN_RELOAD_IMAGE); + rButton->setToolTip(tr("reload image")); + rButton->setIcon(QIcon(QString::fromUtf8(":/new/prefix1/icons/rotateright.png"))); + connect(rButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(ReloadImage(QTreeWidgetItem*, int))); + + DataTree->topLevelItem(index)->setExpanded(1); + DataTree->topLevelItem(index)->addChild(item); + DataTree->setItemWidget(item, COLUMN_CLOSE_IMAGE, cButton); + DataTree->setItemWidget(item, COLUMN_RELOAD_IMAGE, rButton); + + //set the id of the image + QString id = DataTree->topLevelItem(index)->data(COLUMN_IMAGE_NAME,Qt::UserRole).toString(); + item->setData(COLUMN_IMAGE_NAME,Qt::UserRole,id.toStdString().c_str()); + UpdateTree(); + qApp->processEvents(); + ImageInfoChanged(); + QApplication::restoreOverrideCursor(); + } + else + { + QApplication::restoreOverrideCursor(); + QString error = "Cannot import the new image.\n"; + error += mSlicerManagers[index]->GetLastError().c_str(); + QMessageBox::information(this,tr("Problem reading image !"),error); + } +} + +void vvMainWindow::AddFusionImage() +{ + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + + //check if one fusion image is added + for (int child = 0; child < DataTree->topLevelItem(index)->childCount(); child++) + if (DataTree->topLevelItem(index)->child(child)->data(1,Qt::UserRole).toString() == "fusion") + { + QString error = "Cannot add more than one fusion image\n"; + error += "Please remove first "; + error += DataTree->topLevelItem(index)->child(child)->data(COLUMN_IMAGE_NAME,Qt::DisplayRole).toString(); + QMessageBox::information(this,tr("Problem adding fusion image !"),error); + return; + } + + QString Extensions = "Images ( *.bmp *.png *.jpeg *.jpg *.tif *.mhd *.hdr *.vox)"; + Extensions += ";;All Files (*)"; + QString file = QFileDialog::getOpenFileName(this,tr("Load Fusion image"),mInputPathName,Extensions); + if (!file.isEmpty()) + { + mInputPathName = itksys::SystemTools::GetFilenamePath(file.toStdString()).c_str(); + itk::ImageIOBase::Pointer reader = itk::ImageIOFactory::CreateImageIO( + file.toStdString().c_str(), itk::ImageIOFactory::ReadMode); + reader->SetFileName(file.toStdString().c_str()); + reader->ReadImageInformation(); + std::string component = reader->GetComponentTypeAsString(reader->GetComponentType()); + if (reader) + { + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + vvProgressDialog progress("Opening fusion"); + qApp->processEvents(); + + std::string filename = itksys::SystemTools::GetFilenameWithoutExtension(file.toStdString()).c_str(); + if (mSlicerManagers[index]->SetFusion(file.toStdString(), + reader->GetNumberOfDimensions(), component)) + { + //create an item in the tree with good settings + QTreeWidgetItem *item = new QTreeWidgetItem(); + item->setData(0,Qt::UserRole,file.toStdString().c_str()); + item->setData(1,Qt::UserRole,tr("fusion")); + item->setData(COLUMN_IMAGE_NAME,Qt::DisplayRole,filename.c_str()); + qApp->processEvents(); + + for (int j = 1; j <= 4; j++) + { + item->setData(j,Qt::CheckStateRole,DataTree->topLevelItem(index)->data(j,Qt::CheckStateRole)); + mSlicerManagers[index]->GetSlicer(j-1)->SetActorVisibility("fusion",0, + DataTree->topLevelItem(index)->data(j,Qt::CheckStateRole).toInt()); + } + + //Create the buttons for reload and close + qApp->processEvents(); + QTreePushButton* cButton = new QTreePushButton; + cButton->setItem(item); + cButton->setColumn(COLUMN_CLOSE_IMAGE); + cButton->setToolTip(tr("close image")); + cButton->setIcon(QIcon(QString::fromUtf8(":/new/prefix1/icons/exit.png"))); + connect(cButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(CloseImage(QTreeWidgetItem*, int))); + + QTreePushButton* rButton = new QTreePushButton; + rButton->setItem(item); + rButton->setColumn(COLUMN_RELOAD_IMAGE); + rButton->setToolTip(tr("reload image")); + rButton->setIcon(QIcon(QString::fromUtf8(":/new/prefix1/icons/rotateright.png"))); + connect(rButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(ReloadImage(QTreeWidgetItem*, int))); + + DataTree->topLevelItem(index)->setExpanded(1); + DataTree->topLevelItem(index)->addChild(item); + DataTree->setItemWidget(item, COLUMN_CLOSE_IMAGE, cButton); + DataTree->setItemWidget(item, COLUMN_RELOAD_IMAGE, rButton); + + //set the id of the image + QString id = DataTree->topLevelItem(index)->data(COLUMN_IMAGE_NAME,Qt::UserRole).toString(); + item->setData(COLUMN_IMAGE_NAME,Qt::UserRole,id.toStdString().c_str()); + UpdateTree(); + qApp->processEvents(); + ImageInfoChanged(); + QApplication::restoreOverrideCursor(); + } + else + { + QApplication::restoreOverrideCursor(); + QString error = "Cannot import the new image.\n"; + error += mSlicerManagers[index]->GetLastError().c_str(); + QMessageBox::information(this,tr("Problem reading image !"),error); + } + } + else + { + QString error = "Cannot import the new image.\n"; + QMessageBox::information(this,tr("Problem reading image !"),error); + } + } +} + + +void vvMainWindow::OpenField() +{ + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + //check if a vector field has already been added + for (int child = 0; child < DataTree->topLevelItem(index)->childCount(); child++) + if (DataTree->topLevelItem(index)->child(child)->data(1,Qt::UserRole).toString() == "vector") + { + QString error = "Cannot add more than one vector field\n"; + error += "Please remove first "; + error += DataTree->topLevelItem(index)->child(child)->data(COLUMN_IMAGE_NAME,Qt::DisplayRole).toString(); + QMessageBox::information(this,tr("Problem adding vector field!"),error); + return; + } + + QString Extensions = "Images ( *.mhd)"; + Extensions += ";;Images ( *.vf)"; + QString file = QFileDialog::getOpenFileName(this,tr("Load deformation field"),mInputPathName,Extensions); + if (!file.isEmpty()) + AddField(file,index); +} + +void vvMainWindow::AddFieldEntry(QString filename,int index,bool from_disk) +{ + //create an item in the tree with good settings + QTreeWidgetItem *item = new QTreeWidgetItem(); + item->setData(0,Qt::UserRole,filename.toStdString().c_str()); + item->setData(1,Qt::UserRole,tr("vector")); + item->setData(COLUMN_IMAGE_NAME,Qt::DisplayRole,filename); + qApp->processEvents(); + + for (int j = 1; j <= 4; j++) + { + item->setData(j,Qt::CheckStateRole,DataTree->topLevelItem(index)->data(j,Qt::CheckStateRole)); + mSlicerManagers[index]->GetSlicer(j-1)->SetActorVisibility("vector",0, + DataTree->topLevelItem(index)->data(j,Qt::CheckStateRole).toInt()); + } + + //Create the buttons for reload and close + qApp->processEvents(); + QTreePushButton* cButton = new QTreePushButton; + cButton->setItem(item); + cButton->setColumn(COLUMN_CLOSE_IMAGE); + cButton->setToolTip(tr("close vector field")); + cButton->setIcon(QIcon(QString::fromUtf8(":/new/prefix1/icons/exit.png"))); + connect(cButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(CloseImage(QTreeWidgetItem*, int))); + + QTreePushButton* rButton = new QTreePushButton; + rButton->setItem(item); + rButton->setColumn(COLUMN_RELOAD_IMAGE); + rButton->setToolTip(tr("reload vector field")); + rButton->setEnabled(from_disk); + rButton->setIcon(QIcon(QString::fromUtf8(":/new/prefix1/icons/rotateright.png"))); + connect(rButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(ReloadImage(QTreeWidgetItem*, int))); + + DataTree->topLevelItem(index)->setExpanded(1); + DataTree->topLevelItem(index)->addChild(item); + DataTree->setItemWidget(item, COLUMN_RELOAD_IMAGE, rButton); + DataTree->setItemWidget(item, COLUMN_CLOSE_IMAGE, cButton); + + //set the id of the image + QString id = DataTree->topLevelItem(index)->data(COLUMN_IMAGE_NAME,Qt::UserRole).toString(); + item->setData(COLUMN_IMAGE_NAME,Qt::UserRole,id.toStdString().c_str()); + UpdateTree(); + qApp->processEvents(); + ImageInfoChanged(); + QApplication::restoreOverrideCursor(); +} + +void vvMainWindow::AddField(vvImage::Pointer vf,QString file,int index) +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + vvSlicerManager* imageManager = mSlicerManagers[index]; + if (imageManager->SetVF(vf,file.toStdString())) + { + AddFieldEntry(file,index,false); + } + else + { + QString error = "Cannot import the vector field for this image.\n"; + error += imageManager->GetLastError().c_str(); + QMessageBox::information(this,tr("Problem reading VF !"),error); + } + QApplication::restoreOverrideCursor(); +} + +void vvMainWindow::AddField(QString file,int index) +{ + if (QFile::exists(file)) + { + mInputPathName = itksys::SystemTools::GetFilenamePath(file.toStdString()).c_str(); + + //init the progress events + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + vvProgressDialog progress("Opening " + file.toStdString()); + qApp->processEvents(); + + //read the vector and put it in the current mSlicerManager + vvSlicerManager* imageManager = mSlicerManagers[index]; + qApp->processEvents(); + + std::string filename = itksys::SystemTools::GetFilenameWithoutExtension(file.toStdString()).c_str(); + if (imageManager->SetVF(file.toStdString())) + { + imageManager->Render(); + AddFieldEntry(file,index,true); + } + else + { + QApplication::restoreOverrideCursor(); + QString error = "Cannot import the vector field for this image.\n"; + error += imageManager->GetLastError().c_str(); + QMessageBox::information(this,tr("Problem reading VF !"),error); + } + } + else + QMessageBox::information(this,tr("Problem reading VF !"),"File doesn't exist!"); + +} +//==================================================================== + +//==================================================================== +void vvMainWindow::SetVFProperty(int subsampling, int scale, int log) { + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + if (mSlicerManagers[index]->GetSlicer(0)->GetVF()) + { + for (int i = 0; i < 4; i++) + { + mSlicerManagers[index]->GetSlicer(i)->SetVFSubSampling(subsampling); + mSlicerManagers[index]->GetSlicer(i)->SetVFScale(scale); + if (log > 0) + mSlicerManagers[index]->GetSlicer(i)->SetVFLog(1); + else + mSlicerManagers[index]->GetSlicer(i)->SetVFLog(0); + } + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::SetOverlayProperty(int color) { + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + if (mSlicerManagers[index]->GetSlicer(0)->GetOverlay()) + { + mSlicerManagers[index]->SetOverlayColor(color); + mSlicerManagers[index]->SetColorMap(0); + mSlicerManagers[index]->Render(); + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::SetFusionProperty(int opacity, int colormap,double window, double level) { + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + if (mSlicerManagers[index]->GetSlicer(0)->GetFusion()) + { + mSlicerManagers[index]->SetFusionOpacity(opacity); + mSlicerManagers[index]->SetFusionColorMap(colormap); + mSlicerManagers[index]->SetFusionWindow(window); + mSlicerManagers[index]->SetFusionLevel(level); + mSlicerManagers[index]->SetColorMap(0); + mSlicerManagers[index]->Render(); + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::SaveAs() { + if (DataTree->selectedItems()[0]->data(1,Qt::UserRole).toString() == "vector") + { + QMessageBox::warning(this,tr("Unsupported type"),tr("Sorry, saving a vector field is unsupported for the moment")); + return; + } + + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + int dimension = mSlicerManagers[index]->GetDimension(); + QStringList OutputListeFormat; + OutputListeFormat.clear(); + if (dimension == 1) + { + OutputListeFormat.push_back(".mhd"); + } + if (dimension == 2) + { + OutputListeFormat.push_back(".bmp"); + OutputListeFormat.push_back(".png"); + OutputListeFormat.push_back(".jpeg"); + OutputListeFormat.push_back(".tif"); + OutputListeFormat.push_back(".mhd"); + OutputListeFormat.push_back(".hdr"); + OutputListeFormat.push_back(".vox"); + } + else if (dimension == 3) + { + OutputListeFormat.push_back(".mhd"); + OutputListeFormat.push_back(".hdr"); + OutputListeFormat.push_back(".vox"); + } + else if (dimension == 4) + { + OutputListeFormat.push_back(".mhd"); + } + QString Extensions = "AllFiles(*.*)"; + for (int i = 0; i < OutputListeFormat.count(); i++) + { + Extensions += ";;Images ( *"; + Extensions += OutputListeFormat[i]; + Extensions += ")"; + } + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save As"), + mSlicerManagers[index]->GetFileName().c_str(), + Extensions); + if (!fileName.isEmpty()) + { + std::string fileformat = itksys::SystemTools::GetFilenameLastExtension(fileName.toStdString()); + if (OutputListeFormat.contains( + fileformat.c_str())) + { + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + std::string action = "Saving"; + vvProgressDialog progress("Saving "+fileName.toStdString()); + qApp->processEvents(); + vvImageWriter *writer = new vvImageWriter; + writer->SetOutputFileName(fileName.toStdString()); + writer->SetInput(mSlicerManagers[index]->GetImage()); + writer->Update(); + QApplication::restoreOverrideCursor(); + if (writer->GetLastError().size()) + { + QString error = "Saving did not succeed\n"; + error += writer->GetLastError().c_str(); + QMessageBox::information(this,tr("Saving Problem"),error); + SaveAs(); + } + } + else + { + QString error = fileformat.c_str(); + if (error.isEmpty()) + error += "no file format specified !"; + else + error += " format unknown !!!\n"; + QMessageBox::information(this,tr("Saving Problem"),error); + SaveAs(); + } + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::AddLink(QString image1,QString image2) { + for (unsigned int i = 0; i < mSlicerManagers.size();i++) + { + if (image1.toStdString() == mSlicerManagers[i]->GetId()) + { + mSlicerManagers[i]->AddLink(image2.toStdString()); + } + if (image2.toStdString() == mSlicerManagers[i]->GetId()) + { + mSlicerManagers[i]->AddLink(image1.toStdString()); + } + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::RemoveLink(QString image1,QString image2) { + for (unsigned int i = 0; i < mSlicerManagers.size();i++) + { + if (image1.toStdString() == mSlicerManagers[i]->GetId()) + { + mSlicerManagers[i]->RemoveLink(image2.toStdString()); + } + if (image2.toStdString() == mSlicerManagers[i]->GetId()) + { + mSlicerManagers[i]->RemoveLink(image1.toStdString()); + } + } +} +//==================================================================== + +void vvMainWindow::HorizontalSliderMoved(int value,int column, int slicer_index) +{ + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) + { + if (DataTree->topLevelItem(i)->data(column,Qt::CheckStateRole).toInt() > 1) + { + for (int j = 0; j < 4; j++) + { + mSlicerManagers[i]->SetTSliceInSlicer(value,j); + //if (mSlicerManagers[i]->GetSlicer(j)->GetImageActor()->GetVisibility()) + //UpdateTSlice(j,value); + } + mSlicerManagers[i]->GetSlicer(slicer_index)->Render(); + break; + } + } +} + +//==================================================================== +void vvMainWindow::NOHorizontalSliderMoved() { + HorizontalSliderMoved(NOHorizontalSlider->value(),COLUMN_UL_VIEW,0); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::NEHorizontalSliderMoved() { + HorizontalSliderMoved(NEHorizontalSlider->value(),COLUMN_UR_VIEW,1); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::SOHorizontalSliderMoved() { + HorizontalSliderMoved(SOHorizontalSlider->value(),COLUMN_DL_VIEW,2); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::SEHorizontalSliderMoved() { + HorizontalSliderMoved(SEHorizontalSlider->value(),COLUMN_DR_VIEW,3); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::NOVerticalSliderChanged() { + int value = NOVerticalSlider->value(); + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) + { + if (DataTree->topLevelItem(i)->data(COLUMN_UL_VIEW,Qt::CheckStateRole).toInt() > 1) + { + mSlicerManagers[i]->GetSlicer(0)->SetSlice(value); + break; + } + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::NEVerticalSliderChanged() { + int value = NEVerticalSlider->value(); + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) + { + if (DataTree->topLevelItem(i)->data(COLUMN_UR_VIEW,Qt::CheckStateRole).toInt() > 1) + { + mSlicerManagers[i]->GetSlicer(1)->SetSlice(value); + break; + } + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::SOVerticalSliderChanged() { + int value = SOVerticalSlider->value(); + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) + { + if (DataTree->topLevelItem(i)->data(COLUMN_DL_VIEW,Qt::CheckStateRole).toInt() > 1) + { + mSlicerManagers[i]->GetSlicer(2)->SetSlice(value); + break; + } + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::SEVerticalSliderChanged() { + int value = SEVerticalSlider->value(); + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) + { + if (DataTree->topLevelItem(i)->data(COLUMN_DR_VIEW,Qt::CheckStateRole).toInt() > 1) + { + mSlicerManagers[i]->GetSlicer(3)->SetSlice(value); + break; + } + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::UpdateSlice(int slicer, int slice) { + if (slicer == 0) + NOVerticalSlider->setValue(slice); + else if (slicer == 1) + NEVerticalSlider->setValue(slice); + else if (slicer == 2) + SOVerticalSlider->setValue(slice); + else if (slicer == 3) + SEVerticalSlider->setValue(slice); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::UpdateTSlice(int slicer, int slice) { + switch (slicer) + { + case 0: + NOHorizontalSlider->setValue(slice); + break; + case 1: + NEHorizontalSlider->setValue(slice); + break; + case 2: + SOHorizontalSlider->setValue(slice); + break; + case 3: + SEHorizontalSlider->setValue(slice); + break; + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::UpdateSliceRange(int slicer, int min, int max, int tmin, int tmax) { + int position = int((min+max)/2); + int tPosition = int((tmin+tmax)/2); + if (slicer == 0) + { + NOVerticalSlider->setValue(position); + NOVerticalSlider->setRange(min,max); + NOHorizontalSlider->setRange(tmin,tmax); + NOHorizontalSlider->setValue(tPosition); + } + else if (slicer == 1) + { + NEVerticalSlider->setValue(position); + NEVerticalSlider->setRange(min,max); + NEHorizontalSlider->setRange(tmin,tmax); + NEHorizontalSlider->setValue(tPosition); + } + else if (slicer == 2) + { + SOVerticalSlider->setValue(position); + SOVerticalSlider->setRange(min,max); + SOHorizontalSlider->setRange(tmin,tmax); + SOHorizontalSlider->setValue(tPosition); + } + else if (slicer == 3) + { + SEVerticalSlider->setValue(position); + SEVerticalSlider->setRange(min,max); + SEHorizontalSlider->setRange(tmin,tmax); + SEHorizontalSlider->setValue(tPosition); + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::SaveNOScreenshot() { + vtkWindowToImageFilter *w2i = vtkWindowToImageFilter::New(); + w2i->SetInput(NOViewWidget->GetRenderWindow()); + w2i->Update(); + SaveScreenshot(w2i->GetOutput()); + w2i->Delete(); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::SaveNEScreenshot() { + vtkWindowToImageFilter *w2i = vtkWindowToImageFilter::New(); + w2i->SetInput(NEViewWidget->GetRenderWindow()); + w2i->Update(); + SaveScreenshot(w2i->GetOutput()); + w2i->Delete(); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::SaveSOScreenshot() { + vtkWindowToImageFilter *w2i = vtkWindowToImageFilter::New(); + w2i->SetInput(SOViewWidget->GetRenderWindow()); + w2i->Update(); + SaveScreenshot(w2i->GetOutput()); + w2i->Delete(); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::SaveSEScreenshot() { + vtkWindowToImageFilter *w2i = vtkWindowToImageFilter::New(); + w2i->SetInput(SEViewWidget->GetRenderWindow()); + w2i->Update(); + SaveScreenshot(w2i->GetOutput()); + w2i->Delete(); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::SaveScreenshot(vtkImageData* image) { + QString Extensions = "Images( *.png);;"; + Extensions += "Images( *.jpg);;"; + Extensions += "Images( *.bmp);;"; + Extensions += "Images( *.tif);;"; + Extensions += "Images( *.ppm)"; + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save As"), + itksys::SystemTools::GetFilenamePath( + mSlicerManagers[0]->GetFileName()).c_str(), + Extensions); + if (!fileName.isEmpty()) + { + const char *ext = fileName.toStdString().c_str() + strlen(fileName.toStdString().c_str()) - 4; + if (!strcmp(ext, ".bmp")) + { + vtkBMPWriter *bmp = vtkBMPWriter::New(); + bmp->SetInput(image); + bmp->SetFileName(fileName.toStdString().c_str()); + bmp->Write(); + bmp->Delete(); + } + else if (!strcmp(ext, ".tif")) + { + vtkTIFFWriter *tif = vtkTIFFWriter::New(); + tif->SetInput(image); + tif->SetFileName(fileName.toStdString().c_str()); + tif->Write(); + tif->Delete(); + } + else if (!strcmp(ext, ".ppm")) + { + vtkPNMWriter *pnm = vtkPNMWriter::New(); + pnm->SetInput(image); + pnm->SetFileName(fileName.toStdString().c_str()); + pnm->Write(); + pnm->Delete(); + } + else if (!strcmp(ext, ".png")) + { + vtkPNGWriter *png = vtkPNGWriter::New(); + png->SetInput(image); + png->SetFileName(fileName.toStdString().c_str()); + png->Write(); + png->Delete(); + } + else if (!strcmp(ext, ".jpg")) + { + vtkJPEGWriter *jpg = vtkJPEGWriter::New(); + jpg->SetInput(image); + jpg->SetFileName(fileName.toStdString().c_str()); + jpg->Write(); + jpg->Delete(); + } + else + { + QMessageBox::information(this,tr("Problem saving screenshot !"),tr("Cannot save image.\nPlease set a file extension !!!")); + } + } + +} +//==================================================================== + +//==================================================================== +void vvMainWindow::GoToCursor() { + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + for (int column = 1; column < 5; column++) + { + if (DataTree->selectedItems()[0]->data(column,Qt::CheckStateRole).toInt() > 1) + { + double* cursorPos = mSlicerManagers[index]->GetSlicer(column-1)->GetCursorPosition(); + mSlicerManagers[index]->GetSlicer(column-1)->SetCurrentPosition( + cursorPos[0],cursorPos[1],cursorPos[2],cursorPos[3]); + mSlicerManagers[index]->UpdateViews(1,column-1); + mSlicerManagers[index]->UpdateLinked(column-1); + break; + } + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::PlayPause() { + if (playMode) + { + playMode = 0; + playButton->setIcon(QIcon(QString::fromUtf8(":/new/prefix1/icons/player_play.png"))); + ImageInfoChanged(); + return; + } + else + { + int image_number=DataTree->topLevelItemCount(); + bool has_temporal; + for (int i=0;iGetImage()->GetVTKImages().size() > 1) + { + has_temporal=true; + break; + } + if (has_temporal) + { + playMode = 1; + playButton->setIcon(QIcon(QString::fromUtf8(":/new/prefix1/icons/player_pause.png"))); + QTimer::singleShot(1000/mFrameRate, this, SLOT(PlayNext())); + } + } +} +//==================================================================== + +//==================================================================== +void vvMainWindow::PlayNext() { + if (playMode && !this->isHidden()) + { + int image_number=DataTree->topLevelItemCount(); + ///Only play one slicer per SM, and only if the SM is being displayed + for (int i=0;iGetImage()->GetVTKImages().size() > 1 and + DataTree->topLevelItem(i)->data(j+1,Qt::CheckStateRole).toInt() > 0) + { + mSlicerManagers[i]->SetNextTSlice(j); + break; + } + QTimer::singleShot(1000/mFrameRate, this, SLOT(PlayNext())); + } +} +//==================================================================== + +void vvMainWindow::ShowLastImage() +{ + if (mSlicerManagers.size() > 1) + { + QTreeWidgetItem * item=DataTree->topLevelItem(DataTree->topLevelItemCount()-1); + CurrentImageChanged(mSlicerManagers.back()->GetId()); //select new image + item->setData(1,Qt::CheckStateRole,2); //show the new image in the first panel + DisplayChanged(item,1); + } +} + +//==================================================================== +void vvMainWindow::UpdateRenderWindows() { + if (NOViewWidget->GetRenderWindow()) NOViewWidget->GetRenderWindow()->Render(); + if (NEViewWidget->GetRenderWindow()) NEViewWidget->GetRenderWindow()->Render(); + if (SOViewWidget->GetRenderWindow()) SOViewWidget->GetRenderWindow()->Render(); + if (SEViewWidget->GetRenderWindow()) SEViewWidget->GetRenderWindow()->Render(); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::ResampleCurrentImage() { + vvResamplerDialog resampler; + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + resampler.SetSlicerManagers(mSlicerManagers,index); + if (resampler.exec()) + AddImage(resampler.GetOutput(),resampler.GetOutputFileName()); +} +//==================================================================== + +//==================================================================== +void vvMainWindow::SegmentationOnCurrentImage() { + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + + vvSegmentationDialog segmentation; + segmentation.SetImage(mSlicerManagers[index]->GetSlicer(0)->GetImage()); + segmentation.exec(); +} +//==================================================================== + +void vvMainWindow::SurfaceViewerLaunch() +{ + vvSurfaceViewerDialog surfaceViewer; + surfaceViewer.exec(); +} + +//==================================================================== +void vvMainWindow::AddImage(vvImage::Pointer image,std::string filename) +{ + vvSlicerManager* m = new vvSlicerManager(4); + m->SetImage(image); + m->SetFilename(filename); + AddImage(m); +} + +//==================================================================== +void vvMainWindow::AddImage(vvSlicerManager * slicer_manager) { + mSlicerManagers.push_back(slicer_manager); + + std::string filename = slicer_manager->GetFileName(); + + //create an item in the tree with good settings + QTreeWidgetItem *item = new QTreeWidgetItem(); + item->setData(0,Qt::UserRole,slicer_manager->GetFileName().c_str());//files[i].c_str()); + item->setData(COLUMN_IMAGE_NAME,Qt::DisplayRole,filename.c_str()); + qApp->processEvents(); + + for (int j = 1; j <= 4; j++) item->setData(j,Qt::CheckStateRole,1); + + //Create the buttons for reload and close + qApp->processEvents(); + QTreePushButton* cButton = new QTreePushButton; + cButton->setItem(item); + cButton->setColumn(COLUMN_CLOSE_IMAGE); + cButton->setIcon(QIcon(QString::fromUtf8(":/new/prefix1/icons/exit.png"))); + connect(cButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(CloseImage(QTreeWidgetItem*, int))); + + QTreePushButton* rButton = new QTreePushButton; + rButton->setItem(item); + rButton->setColumn(COLUMN_RELOAD_IMAGE); + rButton->setIcon(QIcon(QString::fromUtf8(":/new/prefix1/icons/rotateright.png"))); + rButton->setEnabled(0); + connect(rButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(ReloadImage(QTreeWidgetItem*, int))); + + DataTree->addTopLevelItem(item); + DataTree->setItemWidget(item, COLUMN_CLOSE_IMAGE, cButton); + DataTree->setItemWidget(item, COLUMN_RELOAD_IMAGE, rButton); + + //set the id of the image + QString id = slicer_manager->GetFileName().c_str() + QString::number(mSlicerManagers.size()-1); + item->setData(COLUMN_IMAGE_NAME,Qt::UserRole,id.toStdString().c_str()); + mSlicerManagers.back()->SetId(id.toStdString()); + + linkPanel->addImage(filename, id.toStdString()); + + connect(mSlicerManagers.back(),SIGNAL(currentImageChanged(std::string)), + this,SLOT(CurrentImageChanged(std::string))); + connect(mSlicerManagers.back(),SIGNAL( + UpdatePosition(int, double, double, double, double, double, double, double)),this, + SLOT(MousePositionChanged(int,double, double, double, double, double, double, double))); + connect(mSlicerManagers.back(),SIGNAL(UpdateVector(int, double, double, double, double)), + this, SLOT(VectorChanged(int,double,double,double, double))); + connect(mSlicerManagers.back(),SIGNAL(UpdateOverlay(int, double, double)), + this, SLOT(OverlayChanged(int,double,double))); + connect(mSlicerManagers.back(),SIGNAL(UpdateFusion(int, double)), + this, SLOT(FusionChanged(int,double))); + connect(mSlicerManagers.back(),SIGNAL(UpdateWindows(int, int, int)), + this,SLOT(WindowsChanged(int, int, int))); + connect(mSlicerManagers.back(),SIGNAL(WindowLevelChanged(double, double,int, int)), + this,SLOT(WindowLevelChanged(double, double, int, int))); + connect(mSlicerManagers.back(),SIGNAL(UpdateSlice(int,int)), + this,SLOT(UpdateSlice(int,int))); + connect(mSlicerManagers.back(),SIGNAL(UpdateTSlice(int, int)), + this,SLOT(UpdateTSlice(int, int))); + connect(mSlicerManagers.back(),SIGNAL(UpdateSliceRange(int,int,int,int,int)), + this,SLOT(UpdateSliceRange(int,int,int,int,int))); + connect(mSlicerManagers.back(),SIGNAL(UpdateLinkManager(std::string,int,double,double,double,int)), + this,SLOT(UpdateLinkManager(std::string,int,double,double,double,int))); + connect(mSlicerManagers.back(),SIGNAL(LandmarkAdded()),landmarksPanel,SLOT(AddPoint())); + UpdateTree(); + qApp->processEvents(); + InitSlicers(); + ShowLastImage(); + InitDisplay(); + qApp->processEvents(); + +} +//==================================================================== diff --git a/vv/vvMainWindow.h b/vv/vvMainWindow.h new file mode 100644 index 0000000..553353b --- /dev/null +++ b/vv/vvMainWindow.h @@ -0,0 +1,188 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvMainWindow.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#ifndef vvMainWindow_h +#define vvMainWindow_h + +#include +#include + +#include "ui_vvMainWindow.h" + +#include "vvConstants.h" +#include "vvImage.h" +#include "vvMesh.h" + +class vvSlicerManager; +class vvHelpDialog; +class vvDocumentation; +class vtkRenderWindowInteractor; +class vtkImageData; +class vtkRenderer; +class vvDicomSeriesSelector; + +class vvMainWindow : public QMainWindow, private Ui::vvMainWindow +{ + Q_OBJECT + +public: + vvMainWindow(); + ~vvMainWindow(); + void LoadImages(std::vector filenames, LoadedImageType type); + void AddImage(vvImage::Pointer image,std::string filename); + void AddImage(vvSlicerManager * m); + void AddField(QString file,int index); + void AddOverlayImage(int index, QString filename); + ///Adds a mesh to a SlicerManager, with optional warping by vector field + void AddContour(int image_index, vvMesh::Pointer contour, bool propagation); + ///This is used to show an image when opened or computed + void ShowLastImage(); + +public slots: + ///Allows the user to open and select various surfaces contained in a dicom-struct file + void OpenDCStructContour(); + ///Computes the MIP of the currently selected image and displays it + void ComputeMIP(); + ///Computes the midposition image of a 4D sequence with a VF and displays it + void ComputeMidPosition(); + void OpenImages(); + ///Slot triggered by the dynamically-generated recent file menu actions + void OpenRecentImage(); + void OpenImageWithTime(); + void MergeImages(); + void MergeImagesWithTime(); + void OpenDicom(); + ///Open a vtkPolyData surface mesh and display it over the current image + void OpenVTKContour(); + void SaveAs(); + void CurrentImageChanged(std::string id); + void ImageInfoChanged(); + void ShowHelpDialog(); + void ShowDocumentation(); + void ComputeDeformableRegistration(); + void WarpImage(); + void ChangeViewMode(); + void DisplayChanged(QTreeWidgetItem *item, int column); + void CloseImage(QTreeWidgetItem* item, int column); + void ReloadImage(QTreeWidgetItem* item, int column); + void MousePositionChanged(int visibility, double x, double y, double z, double X, double Y, double Z , double value); + void VectorChanged(int visibility, double x, double y, double z, double value); + void OverlayChanged(int visibility, double valueOver, double valueRef); + void FusionChanged(int visibility, double value); + void ResampleCurrentImage(); + void SegmentationOnCurrentImage(); + void SurfaceViewerLaunch(); + + void WindowsChanged(int window, int view, int slice); + void WindowLevelChanged(double window, double level,int preset, int colormap); + void UpdateSlice(int slicer, int slice); + void UpdateTSlice(int slicer, int slice); + void UpdateSliceRange(int slicer, int min, int max, int tmin, int tmax); + void WindowLevelEdited(); + void UpdateColorMap(); + void UpdateWindowLevel(); + void SwitchWindowLevel(); + void UpdateLinkManager(std::string id, int slicer, double x, double y, double z, int temps); + void AddLink(QString image1,QString image2); + void RemoveLink(QString image1,QString image2); + + ///Generic method called when any one of the horizontal sliders is moved + void HorizontalSliderMoved(int value,int column, int slicer_index); + void NOHorizontalSliderMoved(); + void NEHorizontalSliderMoved(); + void SOHorizontalSliderMoved(); + void SEHorizontalSliderMoved(); + + void NOVerticalSliderChanged(); + void NEVerticalSliderChanged(); + void SOVerticalSliderChanged(); + void SEVerticalSliderChanged(); + + void SaveNEScreenshot(); + void SaveNOScreenshot(); + void SaveSEScreenshot(); + void SaveSOScreenshot(); + + void ShowContextMenu(QPoint point); + void CropImage(); + void SplitImage(); + void CloseImage(); + void ReloadImage(); + void OpenField(); + void SelectOverlayImage(); + void AddFusionImage(); + + void SetVFProperty(int subsampling,int scale,int lut); + void SetOverlayProperty(int color); + void SetFusionProperty(int opacity,int colormap,double window,double level); + + void GoToCursor(); + void PlayPause(); + void PlayNext(); + void ChangeFrameRate(int rate) { + mFrameRate = rate; + } + + void UpdateRenderWindows(); + +private: + + //variables + std::vector mSlicerManagers; + vvHelpDialog *help_dialog; + vvDocumentation *documentation; + vvDicomSeriesSelector *dicomSeriesSelector; + + QString mInputPathName; + bool viewMode; + bool playMode; + + //functions + void UpdateTree(); + ///Adds a vector field to slicer manager index + void WarpImage(vvSlicerManager* selected_slicer,int reference_phase); + void AddFieldEntry(QString filename,int index,bool from_disk); + void AddField(vvImage::Pointer vf,QString file,int index); + void InitDisplay(); + ///Sets the render window and LUT for the last SlicerManager + void InitSlicers(); + void DisplaySliders(int slicer, int window); + QString GetSizeInBytes(unsigned long size); + QString GetVectorDoubleAsString(std::vector vectorDouble); + QString GetVectorIntAsString(std::vector vectorInt); + int GetSlicerIndexFromItem(QTreeWidgetItem* item); + void SaveScreenshot(vtkImageData* image); + + QMenu contextMenu; + //QMenu *AddSubImageMenu; + std::vector contextActions; + std::vector horizontalSliders; + std::vector verticalSliders; + int mFrameRate; +}; + +#endif diff --git a/vv/vvMaximumIntensityProjection.cxx b/vv/vvMaximumIntensityProjection.cxx new file mode 100644 index 0000000..3014720 --- /dev/null +++ b/vv/vvMaximumIntensityProjection.cxx @@ -0,0 +1,77 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#include +#include + +#include "clitkCommon.h" +#include "vvSlicerManager.h" +#include "vvSlicer.h" +#include "vvToITK.h" +#include "vvFromITK.h" +#include "vvMaximumIntensityProjection.h" + +void vvMaximumIntensityProjection::Compute(vvSlicerManager * slicer_manager) +{ +#define TRY_TYPE(TYPE) \ +if (clitk::IsSameType(image->GetScalarTypeAsString())) { this->Update_WithPixelType(image); return; } + std::string list = clitk::CreateListOfTypes(); + vvImage::Pointer image=slicer_manager->GetSlicer(0)->GetImage(); + TRY_TYPE(float); + TRY_TYPE(short); + std::cerr << "Error, I don't know the type '" << image->GetScalarTypeAsString() << "' for the input image. " + << std::endl << "Known types are " << list << std::endl; + exit(0); +#undef TRY_TYPE +} + +template +void vvMaximumIntensityProjection::Update_WithPixelType(vvImage::Pointer image) +{ + switch(image->GetNumberOfDimensions()) + { + case 3: + Update_WithDimAndPixelType(image); + break;; + case 4: + Update_WithDimAndPixelType(image); + break;; + default: + DD("Error: dimension not handled."); + } +} + +template +void vvMaximumIntensityProjection::Update_WithDimAndPixelType(vvImage::Pointer image) +{ + typedef itk::Image ImageType; + typedef itk::Image OutputImageType; + typedef itk::MaximumProjectionImageFilter FilterType; + typename FilterType::Pointer filter = FilterType::New(); + filter->SetProjectionDimension(Dim-1); + typename ImageType::ConstPointer input = vvImageToITK(image); + filter->SetInput(input); + filter->Update(); + mOutputImage=vvImageFromITK(filter->GetOutput()); +} diff --git a/vv/vvMaximumIntensityProjection.h b/vv/vvMaximumIntensityProjection.h new file mode 100644 index 0000000..39eee1f --- /dev/null +++ b/vv/vvMaximumIntensityProjection.h @@ -0,0 +1,45 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + Program: vv + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvMaximumIntensityProjection_h +#define vvMaximumIntensityProjection_h + +#include "vvImage.h" +class vvSlicerManager; + +class vvMaximumIntensityProjection +{ +public: + vvMaximumIntensityProjection() {}; + ///Computes the MIP image on the given vvImage + void Compute(vvSlicerManager*); + vvImage::Pointer GetOutput() {return mOutputImage;}; + +protected: + template void Update_WithDimAndPixelType(vvImage::Pointer); + template void Update_WithPixelType(vvImage::Pointer); + vvImage::Pointer mOutputImage; +}; + +#endif diff --git a/vv/vvMesh.cxx b/vv/vvMesh.cxx new file mode 100644 index 0000000..4ca03cc --- /dev/null +++ b/vv/vvMesh.cxx @@ -0,0 +1,225 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "clitkCommon.h" +#include "vvMesh.h" +#include +#include +#include +#include + +#include + +vvMesh::vvMesh() : + r(1),g(0),b(0), + slice_spacing(-1) +{} + +void vvMesh::AddMesh(vtkPolyData* p) +{ + vtkPolyData * mesh=vtkPolyData::New(); + mesh->ShallowCopy(p); + meshes.push_back(mesh); +} + +void vvMesh::ReadFromVTK(const char * filename) +{ + assert(GetNumberOfMeshes() == 0); ///We assume the object is empty + vtkSmartPointer r=vtkSmartPointer::New(); + r->SetFileName(filename); + r->Update(); + AddMesh(r->GetOutput()); + structure_name=filename; +} + +void vvMesh::RemoveMeshes() +{ + for (std::vector::const_iterator i=meshes.begin();i!=meshes.end();i++) + (*i)->Delete(); + meshes.erase(meshes.begin(),meshes.end()); +} + +void vvMesh::AddMask(vtkImageData* im) +{ + assert(im->GetScalarType() == VTK_UNSIGNED_CHAR); + vtkImageData* image=vtkImageData::New(); + image->ShallowCopy(im); + masks.push_back(image); +} + +void vvMesh::RemoveMasks() +{ + for (std::vector::const_iterator i=masks.begin();i!=masks.end();i++) + (*i)->Delete(); + masks.erase(masks.begin(),masks.end()); +} + +vvMesh::~vvMesh() +{ + RemoveMeshes(); + RemoveMasks(); +} + +void vvMesh::CopyInformation(vvMesh::Pointer input) +{ + r=input->r; + g=input->g; + b=input->b; + structure_name=input->structure_name; + slice_spacing=input->slice_spacing; +} + +void vvMesh::Print() const +{ + std::cout << this << " : " << structure_name << std::endl << "RGB: " << r << "," << g << "," << b << std::endl; + for (std::vector::const_iterator i=meshes.begin();i!=meshes.end();i++) + { + std::cout << (*i)->GetNumberOfPoints() << " points, " << (*i)->GetNumberOfCells() << " cells." << std::endl; + DDV((*i)->GetBounds(),6); + } + std::cout << "-------------------------" << std::endl << std::endl; +} + +void vvMesh::ComputeMasks(vtkImageData* sample,bool extrude) +{ + this->RemoveMasks(); + for (std::vector::iterator i=meshes.begin();i!=meshes.end();i++) + { + vtkPolyData* mesh=*i; + double *bounds=mesh->GetBounds(); + + vtkSmartPointer binary_image=vtkSmartPointer::New(); + binary_image->SetScalarTypeToUnsignedChar(); + ///Use the smallest mask in which the mesh fits + // Add two voxels on each side to make sure the mesh fits + double * samp_origin=sample->GetOrigin(); + double * spacing=sample->GetSpacing(); + binary_image->SetSpacing(spacing); + /// Put the origin on a voxel to avoid small skips + binary_image->SetOrigin(floor((bounds[0]-samp_origin[0])/spacing[0]-2)*spacing[0]+samp_origin[0], + floor((bounds[2]-samp_origin[1])/spacing[1]-2)*spacing[1]+samp_origin[1], + floor((bounds[4]-samp_origin[2])/spacing[2]-2)*spacing[2]+samp_origin[2]); + double * origin=binary_image->GetOrigin(); + binary_image->SetExtent(0,ceil((bounds[1]-origin[0])/spacing[0]+4), + 0,ceil((bounds[3]-origin[1])/spacing[1]+4), + 0,ceil((bounds[5]-origin[2])/spacing[2])+4); + binary_image->AllocateScalars(); + memset(binary_image->GetScalarPointer(),0,binary_image->GetDimensions()[0]*binary_image->GetDimensions()[1]*binary_image->GetDimensions()[2]*sizeof(unsigned char)); + + + vtkSmartPointer sts=vtkSmartPointer::New(); + //The following line is extremely important + //http://www.nabble.com/Bug-in-vtkPolyDataToImageStencil--td23368312.html#a23370933 + sts->SetTolerance(0); + sts->SetInformationInput(binary_image); + + if (extrude) + { + vtkSmartPointer extrude=vtkSmartPointer::New(); + extrude->SetInput(mesh); + ///We extrude in the -slice_spacing direction to respect the FOCAL convention + extrude->SetVector(0, 0, -slice_spacing); + sts->SetInput(extrude->GetOutput()); + } + else + sts->SetInput(mesh); + + vtkSmartPointer stencil=vtkSmartPointer::New(); + stencil->SetStencil(sts->GetOutput()); + stencil->SetInput(binary_image); + stencil->Update(); + this->AddMask(stencil->GetOutput()); + //vtkSmartPointer w = vtkSmartPointer::New(); + //w->SetInput(stencil->GetOutput()); + //w->SetFileName("binary.mhd"); + //w->Write(); + } +} + +void vvMesh::ComputeMeshes() +{ + this->RemoveMeshes(); + for (std::vector::iterator i=masks.begin();i!=masks.end();i++) + { + vtkSmartPointer marching = vtkSmartPointer::New(); + marching->SetInput(*i); + marching->SetValue(0,0.5); + marching->Update(); + this->AddMesh(marching->GetOutput()); + } +} + +void vvMesh::propagateContour(vvImage::Pointer vf) +{ + assert(this->GetNumberOfMeshes() == 1); + std::vector sgrids=vf->GetVTKImages(); + vtkSmartPointer reference_mesh = vtkSmartPointer::New(); + reference_mesh->ShallowCopy(this->GetMesh(0)); + this->RemoveMeshes(); + + for (std::vector::iterator i=sgrids.begin(); + i!=sgrids.end();i++) + { + vtkPolyData* new_mesh=vtkPolyData::New(); + new_mesh->DeepCopy(reference_mesh); + double Ox=vf->GetOrigin()[0]; + double Oy=vf->GetOrigin()[1]; + double Oz=vf->GetOrigin()[2]; + double Sx=vf->GetSpacing()[0]; + double Sy=vf->GetSpacing()[1]; + double Sz=vf->GetSpacing()[2]; + int *dims=vf->GetVTKImages()[0]->GetDimensions(); + assert((*i)->GetScalarType() == VTK_FLOAT); //vfs are assumed to be of float type + assert((*i)->GetNumberOfScalarComponents() == 3); + float * vector_data=reinterpret_cast((*i)->GetScalarPointer()); + for (int j=0;jGetNumberOfPoints();j++) + { + double* old=new_mesh->GetPoint(j); + int ix=(old[0]-Ox)/Sx; + int iy=(old[1]-Oy)/Sy; + int iz=(old[2]-Oz)/Sz; + float* vector=vector_data+(ix+iy*vf->GetSize()[0]+iz*vf->GetSize()[0]*vf->GetSize()[1])*3; + if (ix>=0 and ix < dims[0] + and iy>=0 and iy < dims[1] + and iz>=0 and iz < dims[2]) + new_mesh->GetPoints()->SetPoint(j,old[0]+vector[0],old[1]+vector[1],old[2]+vector[2]); + } + this->AddMesh(new_mesh); + } + if (GetNumberOfMasks()) //If the input mesh has a mask, use it to compute the warped meshes' masks + { + vtkSmartPointer ref_mask = vtkSmartPointer::New(); + ref_mask->ShallowCopy(GetMask(0)); + this->ComputeMasks(ref_mask); + } +} diff --git a/vv/vvMesh.h b/vv/vvMesh.h new file mode 100644 index 0000000..ce5db14 --- /dev/null +++ b/vv/vvMesh.h @@ -0,0 +1,91 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + Program: vv + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvMesh_h +#define vvMesh_h + +#include +#include +#include + +#include + +#include "vvImage.h" + +class vtkPolyData; +class vtkImageData; + +/** A vvMesh is assumed to be either a 3D closed surface + * or a series of surfaces + * It uses a dual representation: both binary mask and mesh**/ +class vvMesh : public itk::LightObject +{ +public: + typedef vvMesh Self; + typedef itk::SmartPointer Pointer; + itkNewMacro(Self); + + void ReadFromVTK(const char * filename); + std::string structure_name; + ///Contour color, [0,1] + double r,g,b; + + vtkPolyData* GetMesh(unsigned int i) const {return meshes[i];} + void AddMesh(vtkPolyData* p); + ///Removes all meshes in the object + void RemoveMeshes(); + unsigned int GetNumberOfMeshes() { return meshes.size(); } + + vtkImageData* GetMask(unsigned int i) const {return masks[i];} + void AddMask(vtkImageData* im); + void RemoveMasks(); + unsigned int GetNumberOfMasks() { return masks.size(); } + + ///Pretty-print information about the mesh + void Print() const; + ///Copies the meta-informations from another mesh + void CopyInformation(vvMesh::Pointer input); + void SetSpacing(double spacing) {slice_spacing=spacing;} + double GetSpacing() {return slice_spacing;} + ///Recompute the meshes from the masks + void ComputeMeshes(); + /**Recompute the masks from the meshes. + * extrude means that the mesh must be extruded before binarizing, + * which is useful when creating a mesh from a stack of slices */ + void ComputeMasks(vtkImageData* sample,bool extrude=false); + ///Create a new vvMesh by propagating the mesh with a displacement VF + void propagateContour(vvImage::Pointer vf); +protected: + ///The spacing between the planar contour, assumed to be constant + double slice_spacing; + std::vector meshes; + std::vector masks; + + vvMesh(); + ~vvMesh(); +}; + +///Propagate a contour using a vector of motion fields, returns a 4D contour + +#endif diff --git a/vv/vvMeshActor.cxx b/vv/vvMeshActor.cxx new file mode 100644 index 0000000..80074b6 --- /dev/null +++ b/vv/vvMeshActor.cxx @@ -0,0 +1,130 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#include "vvMeshActor.h" +#include "clitkCommon.h" +#include +#include +#include +#include +#include +#include +#include + +vvMeshActor::vvMeshActor() : + mCutDimension(NULL), mMesh(NULL), + mMarching(NULL), mMapper(NULL), + mActor(NULL), + mSuperpostionMode(false), mTimeSlice(0) +{} + +vvMeshActor::~vvMeshActor() +{ + mMarching->Delete(); + mMapper->Delete(); + mActor->Delete(); +} + +void vvMeshActor::Init(vvMesh::Pointer mesh,int time_slice,vvImage::Pointer vf) +{ + mMesh=mesh; + + mMarching=vtkMarchingSquares::New(); + mTimeSlice=time_slice; + if (static_cast(time_slice)GetNumberOfMeshes()) + mMarching->SetInput(mMesh->GetMask(time_slice)); + else + mMarching->SetInput(mMesh->GetMask(0)); + mMarching->SetValue(0,0.5); + //mMarching->Update(); + + mMapper=vtkPolyDataMapper::New(); + mMapper->SetInput(mMarching->GetOutput()); + //The following line allows to display the contour over the image + //(http://www.nabble.com/What-happens-when-two-actors-are-at-the-same-depth--td23175458.html) + vtkMapper::SetResolveCoincidentTopologyToPolygonOffset(); + mActor=vtkActor::New(); + mActor->SetMapper(mMapper); + mActor->SetPickable(false); + mActor->GetProperty()->EdgeVisibilityOn(); + mActor->GetProperty()->SetEdgeColor(mMesh->r,mMesh->g,mMesh->b); + mActor->GetProperty()->SetLineWidth(2.); +} + +void vvMeshActor::SetCutSlice(double slice) +{ + mCutSlice=slice; + vtkImageData* mask; + if (static_cast(mTimeSlice)GetNumberOfMasks()) + mask=mMesh->GetMask(mTimeSlice); + else + mask=mMesh->GetMask(0); + int* dims=mask->GetDimensions(); + int mask_slice=(slice-mask->GetOrigin()[mCutDimension])/mask->GetSpacing()[mCutDimension]; + switch (mCutDimension) + { + case 0: + mMarching->SetImageRange(mask_slice,mask_slice,0,dims[1],0,dims[2]); + break; + case 1: + mMarching->SetImageRange(0,dims[0],mask_slice,mask_slice,0,dims[2]); + break; + case 2: + mMarching->SetImageRange(0,dims[0],0,dims[1],mask_slice,mask_slice); + break; + default: + assert(false); + } + mMarching->Update(); +} + +void vvMeshActor::SetTimeSlice(int time) +{ + mTimeSlice=time; + if (static_cast(time)GetNumberOfMasks()) + mMarching->SetInput(mMesh->GetMask(time)); + else + mMarching->SetInput(mMesh->GetMask(0)); + SetCutSlice(mCutSlice); //We need to find the new mask cut slice, + //since masks do not all have the same origin +} + +void vvMeshActor::SetSlicingOrientation(unsigned int d) +{ + mCutDimension=d; +} + +void vvMeshActor::ToggleSuperposition() +{ + DD("Warning: superposition not implemented"); + // std::cout << "vvMeshActor::ToggleSuperposition size = " << mMeshes.size() << std::endl; + if (not mSuperpostionMode and mMesh->GetNumberOfMeshes() > 1) + { + mSuperpostionMode=true; + } + else + { + mSuperpostionMode=false; + } +} diff --git a/vv/vvMeshActor.h b/vv/vvMeshActor.h new file mode 100644 index 0000000..9046f81 --- /dev/null +++ b/vv/vvMeshActor.h @@ -0,0 +1,69 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + Program: vv + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvMeshActor_h +#define vvMeshActor_h + +#include "vvMesh.h" +#include "vvImage.h" + +class vtkActor; +class vtkPolyDataMapper; +class vtkMarchingSquares; +class vtkImageData; + +/** An actor that takes a vvMesh as input, and displays it + ** sliced along the given slice plane */ +class vvMeshActor +{ +public: + vvMeshActor(); + ///Sets slicing orientation + void SetSlicingOrientation(unsigned int d); + ///Changes the cut plane value in real world coordinates + void SetCutSlice(double slice); + /**Initialize the actor and set the inputs. If vf is not null, will use + **it to propagate the contour on all time frames */ + void Init(vvMesh::Pointer mesh,int time_slice, vvImage::Pointer vf=NULL); + ///Set the time slice (only useful when using a 4D contour) + void SetTimeSlice(int time); + ///Toggles between normal 4D mode and superposition mode + void ToggleSuperposition(); + vtkActor* GetActor() {return mActor;} + ~vvMeshActor(); + +protected: + ///0 for x, 1 for y, 2 for z + unsigned int mCutDimension; + vvMesh::Pointer mMesh; + vtkMarchingSquares * mMarching; + vtkPolyDataMapper* mMapper; + vtkActor* mActor; + double mCutPlaneValue; + bool mSuperpostionMode; + int mTimeSlice; + double mCutSlice; +}; + +#endif diff --git a/vv/vvMeshReader.cxx b/vv/vvMeshReader.cxx new file mode 100644 index 0000000..7bae811 --- /dev/null +++ b/vv/vvMeshReader.cxx @@ -0,0 +1,201 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clitkCommon.h" +#include "vvMeshReader.h" +#include "vvProgressDialog.h" + +vvMeshReader::vvMeshReader() : + vtk_mode(false) +{} + +void vvMeshReader::Update() +{ + //Show a progress bar only when opening a DC-struct (ie. multiple contours) + vvProgressDialog progress("Opening " + filename,(not vtk_mode) and (selected_contours.size()>1)); + this->start(); + while (this->isRunning()) + { + progress.SetProgress(result.size(),selected_contours.size()); + this->wait(50); + qApp->processEvents(); + } +} + +void vvMeshReader::run() +{ + ///Verify the important stuff has been set + assert(filename != ""); + if (vtk_mode) //Read vtkPolyData + { + vvMesh::Pointer m=vvMesh::New(); + m->ReadFromVTK(filename.c_str()); + if (vf) m->propagateContour(vf); + result.push_back(m); + } + else //Read a Dicom-struct file + { + assert(selected_contours.size() > 0); + assert(image); + std::vector contour_stacks=readSelectedContours(); + for (std::vector::iterator i=contour_stacks.begin(); + i!=contour_stacks.end();i++) + { + (*i)->ComputeMasks(image->GetVTKImages()[0],true); //Remesh the contour + (*i)->ComputeMeshes(); + if (vf) (*i)->propagateContour(vf); + result.push_back(*i); + } + } +} + +template +ElementType parse_value(std::string str) +{ + std::istringstream parser(str); + ElementType value; + parser >> value; + assert(!parser.fail()); + return value; +} + +template +std::vector parse_string(std::string str,char delim) +{ + std::istringstream ss(str); + std::string token; + std::vector result; + while (getline(ss,token,delim)) + { + result.push_back(parse_value(token)); + } + return result; +} + +std::vector > vvMeshReader::GetROINames() +{ + assert(filename!=""); + gdcm::File reader; + reader.SetFileName(filename.c_str()); + reader.SetMaxSizeLoadEntry(16384); + reader.Load(); + + gdcm::SeqEntry * roi_info=reader.GetSeqEntry(0x3006,0x0020); + assert(roi_info); + std::vector > roi_names; + // DD("ici"); + //int n=0; + for (gdcm::SQItem* i=roi_info->GetFirstSQItem();i!=0;i=roi_info->GetNextSQItem()) + if (i->GetEntryValue(0x3006,0x0022)!= gdcm::GDCM_UNFOUND) + roi_names.push_back(make_pair(atoi(i->GetEntryValue(0x3006,0x0022).c_str()),i->GetEntryValue(0x3006,0x0026))); + return roi_names; +} + +std::vector vvMeshReader::readSelectedContours() +{ + gdcm::File reader; + reader.SetFileName(filename.c_str()); + reader.SetMaxSizeLoadEntry(16384); + reader.Load(); + + std::vector result; + gdcm::SeqEntry * rois=reader.GetSeqEntry(0x3006,0x0039); + ///We need to iterate both on the contours themselves, and on the contour info + gdcm::SeqEntry * roi_info=reader.GetSeqEntry(0x3006,0x0020); + gdcm::SQItem* k=roi_info->GetFirstSQItem(); + for(gdcm::SQItem* i=rois->GetFirstSQItem();i!=0;i=rois->GetNextSQItem()) //loop over ROIS + { + assert(k!=0); + vtkSmartPointer append=vtkSmartPointer::New(); + std::istringstream ss(i->GetEntryValue(0x3006,0x0084)); + int roi_number;ss >> roi_number; + if (std::find(selected_contours.begin(),selected_contours.end(),roi_number) != selected_contours.end())//Only read selected ROIs + { + vvMesh::Pointer current_roi=vvMesh::New(); + std::vector rgb=parse_string(i->GetEntryValue(0x3006,0x002a),'\\'); + assert(rgb.size()==3); + current_roi->r=rgb[0]/255; current_roi->g=rgb[1]/255; current_roi->b=rgb[2]/255; + current_roi->structure_name=k->GetEntryValue(0x3006,0x0026); + gdcm::SeqEntry * contours=i->GetSeqEntry(0x3006,0x0040); + double z0=-1; //Used to determine spacing between slices, assumed to be constant + for(gdcm::SQItem* j=contours->GetFirstSQItem();j!=0;j=contours->GetNextSQItem()) //loop over 2D contours + { + std::string contour_type=j->GetEntryValue(0x3006,0x0042); + if (contour_type=="CLOSED_PLANAR ") + { + int point_number=parse_value(j->GetEntryValue(0x3006,0x0046)); + std::vector points=parse_string(j->GetEntryValue(0x3006,0x0050),'\\'); + assert(points.size() == static_cast(point_number)*3); + if (z0 == -1) //First contour + z0=points[2]; + //2nd contour, spacing not yet set. Need to be sure we are on a different slice, + //sometimes there is more than one closed contour per slice + else if (current_roi->GetSpacing()==-1 && points[2] != z0 ) + current_roi->SetSpacing(points[2]-z0); + vtkPolyData * contour=vtkPolyData::New(); + contour->Allocate(); //for cell structures + contour->SetPoints(vtkPoints::New()); + vtkIdType ids[2]; + for (unsigned int idx=0;idxGetPoints()->InsertNextPoint(points[idx],points[idx+1],points[idx+2]); + ids[0]=idx/3;ids[1]=(ids[0]+1)%point_number; //0-1,1-2,...,n-1-0 + contour->GetLines()->InsertNextCell(2,ids); + } + append->AddInput(contour); + } + else if (contour_type == "POINT ") + ; // silently ignore POINT type since we don't need them at the moment + else + std::cerr << "Warning: contour type " << contour_type << " not handled!" << std::endl; + } + append->Update(); + current_roi->AddMesh(append->GetOutput()); + result.push_back(current_roi); + } + else + { + //std::cerr << "Warning: ignoring ROI #" << roi_number << std::endl; + } + k=roi_info->GetNextSQItem(); //increment the second loop variable + } + return result; +} + diff --git a/vv/vvMeshReader.h b/vv/vvMeshReader.h new file mode 100644 index 0000000..54d12e5 --- /dev/null +++ b/vv/vvMeshReader.h @@ -0,0 +1,70 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + Program: vv + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvMeshReader_h +#define vvMeshReader_h + +#include + +#include + +#include "vvImage.h" +#include "vvMesh.h" + +class vvMeshReader : public QThread +{ +public: + ///Returns the contour names present in a dc struct file + std::vector > GetROINames(); + + vvMeshReader(); + void SetFilename(const std::string f) { filename=f; } + void SetModeToVTK() {vtk_mode=true;} + void SetSelectedItems(const std::vector & items) {selected_contours=items;} + void SetImage(vvImage::Pointer im) {image=im;} + void SetPropagationVF(vvImage::Pointer vf) {this->vf=vf;} + std::vector GetOutput() {return result;} + ///Called from the main thread, runs the reader and displays the progress bar + void Update(); + +protected: + void run(); + std::string filename; + ///Indicates if the reader should expect a vtk polydata file instead of a dicom-struct + bool vtk_mode; + ///The list of indexes of contours the reader should read + std::vector selected_contours; + ///Image the mesh will be displayed over, for binarization + vvImage::Pointer image; + std::vector result; + + ///Read a DC-struct file and return an extruded version of the contours + std::vector readSelectedContours(); + ///Vector field used to propagate the contour + vvImage::Pointer vf; + ///Binarize the output of readSelectedContours() and mesh it with a Marching Cubes + void Remesh(vvMesh::Pointer roi); +}; + +#endif diff --git a/vv/vvMidPosition.cxx b/vv/vvMidPosition.cxx new file mode 100644 index 0000000..dc15478 --- /dev/null +++ b/vv/vvMidPosition.cxx @@ -0,0 +1,206 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#include + +#include +#include + +#include "vvMidPosition.h" +#include "clitkCommon.h" +#include "vvFromITK.h" +#include "vvToITK.h" +#include "clitkInvertVFFilter.h" + +vvMidPosition::vvMidPosition() : + slicer_manager(0), error(false), + reference_image_index(0), + p_bar("Computing mid-position...","Cancel", 0,6), + progress(0) +{ +} + +void vvMidPosition::Update() +{ + this->start(); + while (this->isRunning()) + { + this->wait(50); + this->update_progress(); + qApp->processEvents(); + } +} + +//Common typedefs +typedef itk::Vector VFPixelType; +typedef itk::Image VFType; +typedef itk::Image OutputVFType; + +///Internal functions + +///This function averages a vector field along the temporal dimension +// the progress parameter is a reference to a counter used to update the progress dialog +itk::Image,3>::Pointer AverageField(itk::Image,4>::ConstPointer vf,int &progress); +///Warps an image frame using the vf passed in parameter +template vvImage::Pointer WarpRefImage(OutputVFType::Pointer vf,vvImage::Pointer image,int reference_image_index); + +void vvMidPosition::run() +{ + error=true; + if(slicer_manager->GetImage()->GetNumberOfDimensions() != 4) + error_message="Computation of midposition is only supported for 4D image sequences."; + else if (not slicer_manager->GetVF()) + error_message="A VF is required for midposition computation"; + else if (slicer_manager->GetVF()->GetScalarTypeAsString() != "float") + error_message="Please use a vector field of type float."; + else + { + VFType::ConstPointer vf = vvImageToITK(slicer_manager->GetVF()); + OutputVFType::Pointer avg_vf=AverageField(vf,this->progress); + clitk::InvertVFFilter::Pointer inv_filter= + clitk::InvertVFFilter::New(); + inv_filter->SetInput(avg_vf); + inv_filter->Update(); + progress++; + if (slicer_manager->GetImage()->GetScalarTypeAsString() == "short") + this->output=WarpRefImage(inv_filter->GetOutput(),slicer_manager->GetImage(),reference_image_index); + else + { + error_message="Unsupported image pixel type."; + return; + } + progress++; + error=false; + } +} + +template +vvImage::Pointer WarpRefImage(OutputVFType::Pointer vf,vvImage::Pointer image,int reference_image_index) +{ + typedef itk::Image ImageType; + typedef itk::WarpImageFilter > FilterType; + + typename ImageType::ConstPointer input = vvSingleFrameToITK<3,ImagePixelType>(image,reference_image_index); + + //We resample the VF because itk's warp filter doesn't like it when the vf and the image have + //different spacings + typename itk::VectorResampleImageFilter::Pointer + resampler =itk::VectorResampleImageFilter::New(); + resampler->SetInput(vf); + resampler->SetOutputSpacing(input->GetSpacing()); + resampler->SetOutputOrigin(vf->GetOrigin()); + //Calculate the new size so that it contains the vf + typename ImageType::SizeType newSize; + for (unsigned int i=0 ; i <3; i++) + newSize[i]=(unsigned int) (vf->GetLargestPossibleRegion().GetSize()[i]*vf->GetSpacing()[i]/input->GetSpacing()[i]); + resampler->SetSize( newSize); + + typename FilterType::Pointer warp_filter = FilterType::New(); + warp_filter->SetInput(input); + warp_filter->SetDeformationField(resampler->GetOutput()); + warp_filter->SetOutputSpacing(input->GetSpacing()); + warp_filter->SetOutputOrigin(input->GetOrigin()); + warp_filter->SetOutputSize(input->GetLargestPossibleRegion().GetSize()); + warp_filter->SetEdgePaddingValue(-1000); + warp_filter->Update(); + return vvImageFromITK<3,ImagePixelType>(warp_filter->GetOutput()); +} + +itk::Image,3>::Pointer AverageField(itk::Image,4>::ConstPointer vf, int& progress) +{ + progress++; + + VFType::RegionType region4D=vf->GetLargestPossibleRegion(); + VFType::RegionType::SizeType size4D=region4D.GetSize(); + VFType::IndexType index4D=region4D.GetIndex(); + VFType::SpacingType spacing4D=vf->GetSpacing(); + VFType::PointType origin4D=vf->GetOrigin(); + + OutputVFType::RegionType region; + OutputVFType::RegionType::SizeType size; + OutputVFType::IndexType index; + OutputVFType::SpacingType spacing; + OutputVFType::PointType origin; + for (unsigned int i=0; i< 3; i++) + { + size[i]=size4D[i]; + index[i]=index4D[i]; + spacing[i]=spacing4D[i]; + origin[i]=origin4D[i]; + } + region.SetSize(size); + region.SetIndex(index); + OutputVFType::Pointer output= OutputVFType::New(); + output->SetRegions(region); + output->SetSpacing(spacing); + output->SetOrigin(origin); + output->Allocate(); + progress++; + + + // Region iterators + typedef itk::ImageRegionConstIterator IteratorType; + std::vector iterators(size4D[3]); + for (unsigned int i=0; i< size4D[3]; i++) + { + VFType::RegionType regionIt=region4D; + VFType::RegionType::SizeType sizeIt=regionIt.GetSize(); + sizeIt[3]=1; + regionIt.SetSize(sizeIt); + VFType::IndexType indexIt=regionIt.GetIndex(); + indexIt[3]=i; + regionIt.SetIndex(indexIt); + iterators[i]=IteratorType(vf, regionIt); + } + progress++; + + typedef itk::ImageRegionIterator OutputIteratorType; + OutputIteratorType avIt(output, output->GetLargestPossibleRegion()); + + // Average + VFPixelType vector; + VFPixelType zeroVector=itk::NumericTraits::Zero; + + while (!(iterators[0]).IsAtEnd()) + { + vector=zeroVector; + for (unsigned int i=0; i. + +=========================================================================*/ +#ifndef vvMidPosition_h +#define vvMidPosition_h + +#include +#include +#include +#include "vvImage.h" +#include "vvSlicerManager.h" + +class vvMidPosition : public QThread +{ +public: + vvMidPosition(); + + ///Call this to trigger the computation in a separate thread and wait until it's done + void Update(); + vvSlicerManager * slicer_manager; + ///True if there is an error during the computation + bool error; + std::string error_message; + vvImage::Pointer output; + int reference_image_index; +protected: + void run(); + ///This is called everytime the main thread wakes up, and updates a progress bar + void update_progress(); + QProgressDialog p_bar; + ///Counter for the progress bar. We should use a mutex, but it turns out it isn't needed + int progress; +}; + +#endif diff --git a/vv/vvOverlayPanel.cxx b/vv/vvOverlayPanel.cxx new file mode 100644 index 0000000..f76ee4b --- /dev/null +++ b/vv/vvOverlayPanel.cxx @@ -0,0 +1,224 @@ +#ifndef _vvOverlayPanel_CXX +#define _vvOverlayPanel_CXX + +/*========================================================================= + + Program: vv + Module: $RCSfile: vvOverlayPanel.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 200COLUMN_IMAGE_NAME +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#include "vvOverlayPanel.h" + +#include +#include +#include "QTreePushButton.h" + +#include + +//==================================================================== +vvOverlayPanel::vvOverlayPanel(QWidget * parent):QWidget(parent) +{ + setupUi(this); + + vFFrame->hide(); + compareFrame->hide(); + fusionFrame->hide(); + subSamplingSpinBox->setEnabled(0); + scaleSpinBox->setEnabled(0); + lutCheckBox->hide(); + lutCheckBox->setEnabled(0); + connect(subSamplingSpinBox,SIGNAL(editingFinished()),this,SLOT(setVFProperty())); + connect(scaleSpinBox,SIGNAL(editingFinished()),this,SLOT(setVFProperty())); + connect(lutCheckBox,SIGNAL(clicked()),this,SLOT(setVFProperty())); + connect(colorHorizontalSlider,SIGNAL(valueChanged(int)),this,SLOT(setOverlayProperty())); + connect(opacityHorizontalSlider,SIGNAL(valueChanged(int)),this,SLOT(setFusionProperty())); + connect(fusionColorMapComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(setFusionProperty())); + connect(windowSpinBox,SIGNAL(valueChanged(double)),this,SLOT(setFusionProperty())); + connect(levelSpinBox,SIGNAL(valueChanged(double)),this,SLOT(setFusionProperty())); +} + +void vvOverlayPanel::getCurrentImageName(QString name) +{ + QString filename = "Current image : "; + filename += vtksys::SystemTools::GetFilenameWithoutExtension(name.toStdString()).c_str(); + currentImageLabel->setText(filename.toStdString().c_str()); +} + +void vvOverlayPanel::getVFProperty(int subsampling, int scale, int log) +{ + if (subsampling != -1) + { + vFFrame->show(); + vFFrame->setEnabled(1); + subSamplingSpinBox->setEnabled(1); + subSamplingSpinBox->setValue(subsampling); + scaleSpinBox->setEnabled(1); + scaleSpinBox->setValue(scale); + lutCheckBox->setEnabled(1); + if (log > 0) + lutCheckBox->setCheckState(Qt::Checked); + else + lutCheckBox->setCheckState(Qt::Unchecked); + } + else + { + vFFrame->hide(); + vFFrame->setEnabled(0); + subSamplingSpinBox->setEnabled(0); + subSamplingSpinBox->setValue(0); + scaleSpinBox->setEnabled(0); + scaleSpinBox->setValue(0); + lutCheckBox->setEnabled(0); + lutCheckBox->setCheckState(Qt::Unchecked); + } +} + +void vvOverlayPanel::getVFName(QString name) +{ + QString filename = "Deformation Field : "; + filename += vtksys::SystemTools::GetFilenameWithoutExtension(name.toStdString()).c_str(); + vectorFieldNameLabel->setText(filename.toStdString().c_str()); +} + +void vvOverlayPanel::setVFProperty() +{ + emit VFPropertyUpdated(subSamplingSpinBox->value(), + scaleSpinBox->value(), + lutCheckBox->checkState()); +} + +void vvOverlayPanel::getCurrentVectorInfo(int visibility, double x,double y,double z, double value) +{ + QString motion = "Displacement : "; + QString motionValue = "Length : "; + if (visibility) + { + motion += QString::number(x,'f',1) + " "; + motion += QString::number(y,'f',1) + " "; + motion += QString::number(z,'f',1) + " "; + + motionValue += QString::number(value,'f',1); + } + coordinatesLabel->setText(motion); + normLabel->setText(motionValue); +} + +void vvOverlayPanel::getOverlayName(QString name) +{ + QString filename = "Compare with : "; + filename += vtksys::SystemTools::GetFilenameWithoutExtension(name.toStdString()).c_str(); + imageComparedLabel->setText(filename.toStdString().c_str()); +} + +void vvOverlayPanel::getOverlayProperty(int value) +{ + if (value > -1) + { + compareFrame->show(); + compareFrame->setEnabled(1); + colorHorizontalSlider->setEnabled(1); + colorHorizontalSlider->setValue(value); + } + else + { + compareFrame->hide(); + compareFrame->setEnabled(0); + colorHorizontalSlider->setEnabled(0); + colorHorizontalSlider->setValue(0); + } +} + +void vvOverlayPanel::setOverlayProperty() +{ + emit OverlayPropertyUpdated(colorHorizontalSlider->value()); +} + +void vvOverlayPanel::getCurrentOverlayInfo(int visibility,double valueOver, double valueRef) +{ + QString refValue = "Pixel value in image 1 : "; + QString overlayValue = "Pixel value in image 2 : "; + QString diffValue = "Pixel difference : "; + if (visibility) + { + refValue += QString::number(valueRef); + overlayValue += QString::number(valueOver,'f',1); + diffValue += QString::number(valueRef - valueOver,'f',1); + } + refValueLabel->setText(refValue); + valueLabel->setText(overlayValue); + diffValueLabel->setText(diffValue); +} +void vvOverlayPanel::getFusionName(QString name) +{ + QString filename = "Fusion with : "; + filename += vtksys::SystemTools::GetFilenameWithoutExtension(name.toStdString()).c_str(); + dataFusionnedLabel->setText(filename.toStdString().c_str()); +} + +void vvOverlayPanel::getFusionProperty(int opacity, int colormap, double window, double level) +{ + if (opacity > -1) + { + fusionFrame->show(); + fusionFrame->setEnabled(1); + opacityHorizontalSlider->setEnabled(1); + opacityHorizontalSlider->setValue(opacity); + fusionColorMapComboBox->setEnabled(1); + fusionColorMapComboBox->setCurrentIndex(colormap); + windowSpinBox->setEnabled(1); + levelSpinBox->setEnabled(1); + windowSpinBox->setValue(window); + levelSpinBox->setValue(level); + } + else + { + fusionFrame->hide(); + fusionFrame->setEnabled(0); + opacityHorizontalSlider->setEnabled(0); + opacityHorizontalSlider->setValue(0); + fusionColorMapComboBox->setEnabled(0); + fusionColorMapComboBox->setCurrentIndex(-1); + windowSpinBox->setEnabled(0); + levelSpinBox->setEnabled(0); + } +} + +void vvOverlayPanel::setFusionProperty() +{ + emit FusionPropertyUpdated(opacityHorizontalSlider->value(), fusionColorMapComboBox->currentIndex(), + windowSpinBox->value(), levelSpinBox->value()); +} + +void vvOverlayPanel::getCurrentFusionInfo(int visibility,double value) +{ + QString fusionValue = "Pixel value in image 2 : "; + if (visibility) + { + fusionValue += QString::number(value,'f',1); + } + valueFusionnedLabel->setText(fusionValue); +} + +#endif /* end #define _vvOverlayPanel_CXX */ + diff --git a/vv/vvOverlayPanel.h b/vv/vvOverlayPanel.h new file mode 100644 index 0000000..b4a88e0 --- /dev/null +++ b/vv/vvOverlayPanel.h @@ -0,0 +1,76 @@ +#ifndef _vvOverlayPanel_H +#define _vvOverlayPanel_H + +/*========================================================================= + + Program: vv + Module: $RCSfile: vvOverlayPanel.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:58 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 200COLUMN_IMAGE_NAME +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#include +#include + +#include "ui_vvOverlayPanel.h" + +//==================================================================== +class vvOverlayPanel : public QWidget, private Ui::vvOverlayPanel +{ + + Q_OBJECT + +public: + // constructor - destructor + vvOverlayPanel(QWidget * parent=0); + ~vvOverlayPanel() {} + + void getCurrentImageName(QString name); + + void getVFProperty(int subsampling, int scale, int log); + void getVFName(QString name); + + void getOverlayProperty(int color); + void getOverlayName(QString name); + + void getFusionProperty(int opacity, int colormap, double window, double level); + void getFusionName(QString name); + + void getCurrentVectorInfo(int visibility, double x, double y, double z, double value); + void getCurrentOverlayInfo(int visibility,double valueOver, double valueRef); + void getCurrentFusionInfo(int visibility,double value); + +public slots: + void setVFProperty(); + void setOverlayProperty(); + void setFusionProperty(); + +signals: + void VFPropertyUpdated(int subsampling, int scale, int log); + void OverlayPropertyUpdated(int color); + void FusionPropertyUpdated(int opacity, int colormap, double window, double level); + +}; // end class vvOverlayPanel +//==================================================================== + +#endif /* end #define _vvOverlayPanel_H */ + diff --git a/vv/vvProgressDialog.h b/vv/vvProgressDialog.h new file mode 100644 index 0000000..5d46b8f --- /dev/null +++ b/vv/vvProgressDialog.h @@ -0,0 +1,62 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvProgressDialog.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvProgressDialog_h +#define vvProgressDialog_h + +#include "ui_vvProgressDialog.h" +#include + +class vvProgressDialog : public QDialog, private Ui::vvProgressDialog +{ + Q_OBJECT + +public: + vvProgressDialog(std::string message,bool show_progress=false) { + setupUi(this); + textLabel->setText(message.c_str()); + if (show_progress) + progressBar->show(); + else + progressBar->hide(); + this->show(); + } + void Update(std::string message) + { + textLabel->setText(message.c_str()); + } + void SetProgress(unsigned int current,unsigned int max) + { + progressBar->setMaximum(max); + progressBar->setValue(current); + } + ~vvProgressDialog() {} + +public slots: + +}; + +#endif diff --git a/vv/vvQDicomSeriesSelector.cxx b/vv/vvQDicomSeriesSelector.cxx new file mode 100644 index 0000000..225fef8 --- /dev/null +++ b/vv/vvQDicomSeriesSelector.cxx @@ -0,0 +1,310 @@ +/*========================================================================= + +Program: vv +Module: $RCSfile: vvQDicomSeriesSelector.cxx,v $ +Language: C++ +Date: $Date: 2010/01/06 13:31:57 $ +Version: $Revision: 1.1 $ +Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef VVDICOMSERIESSELECTOR_CXX +#define VVDICOMSERIESSELECTOR_CXX + +// itk include +#include +#include +#include +#include + +#include "vvQDicomSeriesSelector.h" +//#include "vvUserConfig.h" + +//==================================================================== +vvDicomSeriesSelector::vvDicomSeriesSelector(QWidget* parent) + :QDialog(parent) { + // Set GUI + ui.setupUi(this); + // Correct GUI for splitter ... + // QSplitter * splitter = new QSplitter(this); + // splitter->setOrientation(Qt::Horizontal); + // ui.gridLayout1->addWidget(splitter, 0, 0, 1, 1); + // ui.mFrameLeft->setParent(splitter); + // ui.mFrameRight->setParent(splitter); + // ui.toolBox->setCurrentIndex(0); + + + + ui.mButtonBox->button(QDialogButtonBox::Open)->setEnabled(false); + + connect(ui.mBrowseButton, SIGNAL(released()), + this, SLOT(BrowseButtonRelease())); + connect(ui.mSearchButton, SIGNAL(released()), + this, SLOT(SearchButtonRelease())); + connect(ui.mListWidget, SIGNAL(itemSelectionChanged()), + this, SLOT(itemSelectionChanged())); + connect(ui.mDicomDetailsListWidget, SIGNAL(itemSelectionChanged()), + this, SLOT(itemDetailsSelectionChanged())); + + // Initialization + /* if (config::get_current_path() != QString(0)) + mFoldername = config::get_current_path(); + else*/ + mFoldername = QFileInfo("./").absolutePath(); + + mPreviousPath = mFoldername; + ui.mFolderLineEdit->setText(mFoldername); + // ui.mTableWidget->setRowCount(0); +} +//==================================================================== + +//==================================================================== +void vvDicomSeriesSelector::show() { + QDialog::show(); + //grabKeyboard(); + // ui.mListWidget->grabKeyboard(); + // ui.mDicomDetailsListWidget->grabKeyboard(); +} +//==================================================================== + +//==================================================================== +void vvDicomSeriesSelector::close() { + QDialog::close(); + // ui.mListWidget->releaseKeyboard() + //releaseKeyboard(); +} +//==================================================================== + +//==================================================================== +void vvDicomSeriesSelector::BrowseButtonRelease() { + QFileDialog dialog(this); + dialog.setFileMode(QFileDialog::AnyFile); + dialog.setFilter("DICOM files (*.dcm); All files (*)"); + mFoldername = dialog.getExistingDirectory(this, + "Select a folder to find DICOM image", + mPreviousPath); + ui.mFolderLineEdit->setText(mFoldername); + mPreviousPath = QFileInfo(mFoldername).absolutePath(); + // config::set_current_path(mPreviousPath); +} +//==================================================================== + +//==================================================================== +void vvDicomSeriesSelector::SearchButtonRelease() { + typedef itk::GDCMSeriesFileNames NamesGeneratorType; + NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New(); + nameGenerator->SetUseSeriesDetails(true); + //nameGenerator->SetDirectory(mFoldername.toStdString()); + nameGenerator->SetRecursive(ui.mIsRecursiveCheckBox->checkState() == Qt::Checked); + + //ds gérer recursive moi-meme pour progress ... + nameGenerator->SetInputDirectory(mFoldername.toStdString()); + + // insert in table + typedef std::vector SeriesIdContainer; + const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs(); + + for (unsigned int i=0; i * filenames = new std::vector; + const std::vector & temp = nameGenerator->GetFileNames(seriesUID[i]); + for (unsigned int j=0; jpush_back(temp[j]); + } + mListOfSeriesFilenames[seriesUID[i]] = filenames; + + // store first header + gdcm::File *header = new gdcm::File(); + header->SetFileName((*filenames)[0]); + header->SetMaxSizeLoadEntry(16384); + header->SetLoadMode(gdcm::LD_NOSHADOW);// don't load shadow tags (in order to save memory) + header->Load(); + + + // + DD(header->GetEntryValue(0x0028,0x0030).c_str()); + + //DS TEST DAVID + DD(header->GetXSize()); + DD(header->GetYSize()); + DD(header->GetZSize()); + DD(header->GetXSpacing()); + DD(header->GetYSpacing()); + DD(header->GetZSpacing()); + DD(header->GetXOrigin()); + DD(header->GetYOrigin()); + DD(header->GetZOrigin()); + DD("\n"); + /* + QString size = QString("%1x%2x%3") + .arg(header->GetXSize()) + .arg(header->GetYSize()) + .arg(header->GetZSize()); + QString spacing = QString("%1x%2x%3") + .arg(header->GetXSpacing()) + .arg(header->GetYSpacing()) + .arg(header->GetZSpacing()); + QString origin = QString("%1x%2x%3") + .arg(header->GetXOrigin()) + .arg(header->GetYOrigin()) + .arg(header->GetZOrigin()); + */ + + + mDicomHeader[seriesUID[i]] = header; + + // new item + QListWidgetItem *newItem = new QListWidgetItem; + newItem->setText(seriesUID[i].c_str()); + ui.mListWidget->insertItem(i, newItem); + + //AddSerieToTheTable(i, *filenames); + } + } +} +//==================================================================== + +//==================================================================== +void vvDicomSeriesSelector::itemSelectionChanged() { + // mLabelSelected.setText( + mCurrentSerie = ui.mListWidget->selectedItems()[0]->text().toStdString(); + mFilenames = mListOfSeriesFilenames[mCurrentSerie]; + ui.mButtonBox->button(QDialogButtonBox::Open)->setEnabled(true); + + if (mDicomInfo[mCurrentSerie] == "") { + // QString m; + // m = QString("Patient : %1
").arg(mDicomHeader[s]->GetEntryValue(0x0010,0x0010).c_str()); // Patient's name + mDicomInfo[mCurrentSerie] = MakeDicomInfo(mCurrentSerie, mDicomHeader[mCurrentSerie]); + } + ui.mDicomInfoPanel->setText(mDicomInfo[mCurrentSerie]); + + // Detail tab + ui.mDicomDetailsListWidget->clear(); + for (unsigned int i=0; isize(); i++) { + QListWidgetItem * newItem = new QListWidgetItem; + newItem->setText(QFileInfo((*mFilenames)[i].c_str()).fileName()); + ui.mDicomDetailsListWidget->insertItem(i, newItem); + } + +} +//==================================================================== + +//==================================================================== +void vvDicomSeriesSelector::itemDetailsSelectionChanged() { + unsigned int i = ui.mDicomDetailsListWidget->currentRow(); + if (isize()) { + if (mDicomDetails[(*mFilenames)[i]] == "") { + std::ostringstream s; + mDicomHeader[mCurrentSerie]->Print(s); + + QString l; + gdcm::File * header = mDicomHeader[mCurrentSerie]; + gdcm::DocEntry * e = header->GetFirstEntry(); + while (e) { + if (e->GetName() != "gdcm::Unknown") { + l += QString("%1 : %2\n") + .arg(e->GetName().c_str()) + .arg((header->GetEntryValue(e->GetGroup(), e->GetElement())).c_str()); + } + e = header->GetNextEntry(); + } + + mDicomDetails[(*mFilenames)[i]] = l.toStdString(); + } + ui.mDicomDetailsLabel->setText(mDicomDetails[(*mFilenames)[i]].c_str()); + } +} +//==================================================================== + +//==================================================================== +QString vvDicomSeriesSelector::MakeDicomInfo(std::string & s, gdcm::File *header) { + QString n = QString("%1").arg(mListOfSeriesFilenames[s]->size()); + QString size = QString("%1x%2x%3") + .arg(header->GetXSize()) + .arg(header->GetYSize()) + .arg(header->GetZSize()); + QString spacing = QString("%1x%2x%3") + .arg(header->GetXSpacing()) + .arg(header->GetYSpacing()) + .arg(header->GetZSpacing()); + QString origin = QString("%1x%2x%3") + .arg(header->GetXOrigin()) + .arg(header->GetYOrigin()) + .arg(header->GetZOrigin()); + QString ss = + //AddInfo( "Serie ID : ", s)+ + AddInfo(header, "Patient : ", 0x0010,0x0010)+ + AddInfo( "Folder : ", QFileInfo((*mFilenames)[0].c_str()).canonicalPath().toStdString())+ + AddInfo(header, "Series Description : ", 0x0008,0x103e)+ + AddInfo(header, "Modality : ", 0x0008,0x0060)+ + AddInfo(header, "# images : ", 0x0020,0x0013)+ + AddInfo( "# files : ", n.toStdString())+ + AddInfo( "Size : ", size.toStdString())+ + AddInfo( "Spacing : ", spacing.toStdString())+ + AddInfo( "Origin : ", origin.toStdString())+ + AddInfo(header, "Pixel size : ", 0x0028,0x0100)+ + AddInfo( "Pixel type : ", header->GetPixelType()); + return ss; +} +//==================================================================== + +//==================================================================== +QString vvDicomSeriesSelector::AddInfo(gdcm::File *header, QString n, uint16_t group, uint16_t elem) { + return AddInfo(n.toStdString(), header->GetEntryValue(group, elem)); +} +//==================================================================== + +//==================================================================== +QString vvDicomSeriesSelector::AddInfo(std::string n, std::string m) { + QString s = QString("%1 %2
"). + arg(n.c_str()).arg(m.c_str()); + return s; +} +//==================================================================== + +//==================================================================== +void vvDicomSeriesSelector::AddSerieToTheTable(int i, std::vector & filenames) { + gdcm::File *header = new gdcm::File(); + header->SetFileName(filenames[0]); + header->SetMaxSizeLoadEntry(16384); + header->SetLoadMode(gdcm::LD_NOSHADOW);// don't load shadow tags (in order to save memory) + header->Load(); + //header->Print(cout); + // ->GetValEntry + // mDicomHeader[] = header; + + /* + + QTableWidgetItem *newItem = new + QTableWidgetItem(QString("# images = %1").arg(header->GetImageNumber())); + // newItem->setCheckState(Qt::Checked); + //newItem->setFlags(!Qt::ItemIsEditable); + DD(ui.mTableWidget->rowCount()); + ui.mTableWidget->setItem(i, 0, newItem); + */ +} +//==================================================================== + +#endif // VVDICOMSERIESSELECTOR_CXX diff --git a/vv/vvQDicomSeriesSelector.h b/vv/vvQDicomSeriesSelector.h new file mode 100644 index 0000000..531e2bb --- /dev/null +++ b/vv/vvQDicomSeriesSelector.h @@ -0,0 +1,76 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvQDicomSeriesSelector.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef VVDICOMSERIESSELECTOR_H +#define VVDICOMSERIESSELECTOR_H + +// vv include +#include "ui_vvDicomSeriesSelector.h" +#include "clitkCommon.h" +#include "vvQProgressDialogITKCommand.h" + +namespace gdcm {class File;} + +// qt include +#include +#include + +class vvDicomSeriesSelector : public QDialog { + Q_OBJECT + +public: + vvDicomSeriesSelector(QWidget * parent=0); + virtual void show(); + virtual void close(); + std::vector * GetFilenames() { + return mFilenames; + } + +protected slots: + void BrowseButtonRelease(); + void SearchButtonRelease(); + void itemSelectionChanged(); + void itemDetailsSelectionChanged(); + +protected: + QString mPreviousPath; + QString mFoldername; + void AddSerieToTheTable(int i, std::vector & filenames); + QString MakeDicomInfo(std::string & s, gdcm::File *header); + QString AddInfo(gdcm::File *header, QString n, unsigned short group, unsigned short elem); + QString AddInfo(std::string n, std::string m); + +private: + Ui::vvDicomSeriesSelector ui; + std::string mCurrentSerie; + std::map* > mListOfSeriesFilenames; + std::vector * mFilenames; + std::map mDicomInfo; + std::map mDicomHeader; + std::map mDicomDetails; +}; + +#endif // VVDICOMSERIESSELECTOR_H diff --git a/vv/vvQProgressDialogITKCommand.cxx b/vv/vvQProgressDialogITKCommand.cxx new file mode 100644 index 0000000..5a50125 --- /dev/null +++ b/vv/vvQProgressDialogITKCommand.cxx @@ -0,0 +1,68 @@ +/*========================================================================= + +Program: vv +Module: $RCSfile: vvQProgressDialogITKCommand.cxx,v $ +Language: C++ +Date: $Date: 2010/01/06 13:31:57 $ +Version: $Revision: 1.1 $ +Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef VVQPROGRESSDIALOGITKCOMMAND_CXX +#define VVQPROGRESSDIALOGITKCOMMAND_CXX + +#include "clitkIOCommon.h" +#include "vvQProgressDialogITKCommand.h" + +//==================================================================== +vvQProgressDialogITKCommand::vvQProgressDialogITKCommand() { + progress.setWindowModality(Qt::WindowModal); + progress.setCancelButtonText("Cancel"); +} +//==================================================================== + +//==================================================================== +void vvQProgressDialogITKCommand::Initialize(QString title, float sec, int max) { + progress.setMinimumDuration((int)lrint(1000.0*sec)); // number of seconds to wait before displaying dialog + progress.setLabelText(title); + i=0; + progress.setMaximum(max); +} +//==================================================================== + +//==================================================================== +void vvQProgressDialogITKCommand::Execute(itk::Object *caller, const itk::EventObject & event) { + i++; + progress.setValue(i); + if (progress.wasCanceled()) { + itk::ProcessObject * o = dynamic_cast(caller); + o->SetAbortGenerateData(true); + } +} +//==================================================================== + +//==================================================================== +void vvQProgressDialogITKCommand::Execute(const itk::Object *caller, const itk::EventObject & event) { + i++; + progress.setValue(i); +} +//==================================================================== + +#endif /* end #define VVQPROGRESSDIALOGITKCOMMAND_CXX */ + diff --git a/vv/vvQProgressDialogITKCommand.h b/vv/vvQProgressDialogITKCommand.h new file mode 100644 index 0000000..d24561e --- /dev/null +++ b/vv/vvQProgressDialogITKCommand.h @@ -0,0 +1,59 @@ +/*========================================================================= + +Program: vv +Module: $RCSfile: vvQProgressDialogITKCommand.h,v $ +Language: C++ +Date: $Date: 2010/01/06 13:31:58 $ +Version: $Revision: 1.1 $ +Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef VVQPROGRESSDIALOGITKCOMMAND_H +#define VVQPROGRESSDIALOGITKCOMMAND_H + + +// itk include +#include "itkCommand.h" + +// qt include +#include + +class vvQProgressDialogITKCommand : public itk::Command { + +public: + typedef vvQProgressDialogITKCommand Self; + typedef itk::Command Superclass; + typedef itk::SmartPointer Pointer; + + itkNewMacro(Self); + + void Initialize(QString title, float sec, int max); + + void Execute(itk::Object *caller, const itk::EventObject & event); + void Execute(const itk::Object *caller, const itk::EventObject & event); + +protected: + vvQProgressDialogITKCommand(); + QProgressDialog progress; + int i; + +}; // end class vvQProgressDialogITKCommand + +#endif /* end #define VVQPROGRESSDIALOGITKCOMMAND_H */ + diff --git a/vv/vvResamplerDialog.cxx b/vv/vvResamplerDialog.cxx new file mode 100644 index 0000000..0a0b8e9 --- /dev/null +++ b/vv/vvResamplerDialog.cxx @@ -0,0 +1,481 @@ +#ifndef _vvResamplerDialog_CXX +#define _vvResamplerDialog_CXX + +/*========================================================================= + +Program: vv +Module: $RCSfile: vvResamplerDialog.cxx,v $ +Language: C++ +Date: $Date: 2010/01/06 13:31:58 $ +Version: $Revision: 1.1 $ +Author : David Sarrut (david.sarrut@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#include "vvResamplerDialog.h" +#include "clitkImageResampleGenericFilter.h" +#include "vvSlicer.h" + +#include +#include + +#define COLUMN_IMAGE_NAME 7 + +//==================================================================== +vvResamplerDialog::vvResamplerDialog(QWidget * parent, Qt::WindowFlags f) + :QDialog(parent,f), Ui::vvResamplerDialog() { + + // initialization + setupUi(this); + Init(); + + // Connect signals & slots + connect(this, SIGNAL(accepted()), this, SLOT(Resample())); + connect(mImagesComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(UpdateCurrentInputImage())); + + connect(sizeRadioButton, SIGNAL(clicked()), this, SLOT(UpdateControlSizeAndSpacing())); + connect(scaleSizeRadioButton, SIGNAL(clicked()), this, SLOT(UpdateControlSizeAndSpacing())); + connect(isoSizeRadioButton, SIGNAL(clicked()), this, SLOT(UpdateControlSizeAndSpacing())); + connect(spacingRadioButton, SIGNAL(clicked()), this, SLOT(UpdateControlSizeAndSpacing())); + connect(scaleSpacingRadioButton, SIGNAL(clicked()), this, SLOT(UpdateControlSizeAndSpacing())); + connect(isoSpacingRadioButton, SIGNAL(clicked()), this, SLOT(UpdateControlSizeAndSpacing())); + + connect(xSizeLineEdit, SIGNAL(textEdited(QString)),this,SLOT(ComputeNewSpacingFromSize())); + connect(ySizeLineEdit, SIGNAL(textEdited(QString)),this,SLOT(ComputeNewSpacingFromSize())); + connect(zSizeLineEdit, SIGNAL(textEdited(QString)),this,SLOT(ComputeNewSpacingFromSize())); + connect(xSpacingLineEdit, SIGNAL(textEdited(QString)),this,SLOT(ComputeNewSizeFromSpacing())); + connect(ySpacingLineEdit, SIGNAL(textEdited(QString)),this,SLOT(ComputeNewSizeFromSpacing())); + connect(zSpacingLineEdit, SIGNAL(textEdited(QString)),this,SLOT(ComputeNewSizeFromSpacing())); + connect(scaleSizeLineEdit,SIGNAL(textEdited(QString)),this,SLOT(ComputeNewSizeFromScale())); + connect(scaleSpacingLineEdit,SIGNAL(textEdited(QString)),this,SLOT(ComputeNewSpacingFromScale())); + connect(isoSizeLineEdit,SIGNAL(textEdited(QString)),this,SLOT(ComputeNewSizeFromIso())); + connect(isoSpacingLineEdit,SIGNAL(textEdited(QString)),this,SLOT(ComputeNewSpacingFromIso())); + + connect(gaussianFilterCheckBox,SIGNAL(stateChanged(int)),this,SLOT(UpdateGaussianFilter())); + connect(interpolationComboBox,SIGNAL(currentIndexChanged(QString)),this,SLOT(UpdateInterpolation())); +} +//==================================================================== + +//==================================================================== +void vvResamplerDialog::Init() { + mLastError =""; + + mInputFileFormat = ""; + ComponentType = ""; + mPixelType = ""; + + mInputSize.resize(0); + mInputSpacing.resize(0); + mInputOrigin.resize(0); + mOutputSize.resize(0); + mOutputSpacing.resize(0); + + xSizeLineEdit->setText(""); + ySizeLineEdit->setText(""); + zSizeLineEdit->setText(""); + xSpacingLineEdit->setText(""); + ySpacingLineEdit->setText(""); + zSpacingLineEdit->setText(""); + scaleSizeLineEdit->setText(""); + scaleSpacingLineEdit->setText(""); + + sizeRadioButton->setChecked(0); + scaleSizeRadioButton->setChecked(0); + isoSizeRadioButton->setChecked(0); + spacingRadioButton->setChecked(0); + scaleSpacingRadioButton->setChecked(0); + isoSpacingRadioButton->setChecked(0); + + gaussianFilterCheckBox->setCheckState(Qt::Unchecked); + + xGaussianLineEdit->hide(); + yGaussianLineEdit->hide(); + zGaussianLineEdit->hide(); + gaussianFilterLabel->hide(); + + bSplineLabel->hide(); + bSplineOrderSpinBox->hide(); + bLUTFactorLabel->hide(); + bLUTSpinBox->hide(); + mDimension = -1; + + QPalette qPalette; + qPalette.setColor(QPalette::Foreground, QColor(Qt::blue)); + mInputFormatLabel->setPalette(qPalette); + mInputDimLabel->setPalette(qPalette); + mInputPixelTypeLabel->setPalette(qPalette); + mInputSizeLabel->setPalette(qPalette); + mInputSpacingLabel->setPalette(qPalette); + + UpdateCurrentInputImage(); +} +//==================================================================== + +//==================================================================== +void vvResamplerDialog::UpdateCurrentInputImage() { + // Set current image & index + mCurrentIndex = mImagesComboBox->currentIndex(); + if (mCurrentIndex == -1) { + mCurrentImage = NULL; + return ; + } + mCurrentImage = mSlicerManagers[mCurrentIndex]->GetSlicer(0)->GetImage(); + if (mCurrentImage.IsNull()) return; + mInputFileName = mSlicerManagers[mCurrentIndex]->GetFileName().c_str(); + + // Set current information + mPixelType = mCurrentImage->GetScalarTypeAsString().c_str(); + //ds ComponentType = mCurrentImageGetNumberOfScalarComponents(); + mDimension = mCurrentImage->GetNumberOfDimensions(); + + // Copy size, spacing ... + mInputOrigin.resize(mDimension); + mInputSpacing.resize(mDimension); + mInputSize.resize(mDimension); + for (int i = 0; i < mDimension;i++) { + mInputOrigin[i] = mCurrentImage->GetOrigin()[i]; + mInputSpacing[i] = mCurrentImage->GetSpacing()[i]; + mInputSize[i] = mCurrentImage->GetSize()[i]; + } + + // Get file format + mInputFileFormat = itksys::SystemTools::GetFilenameLastExtension(mInputFileName.toStdString()).c_str(); + + // Display infos + mInputFormatLabel->setText(mInputFileFormat); + mInputSizeLabel->setText(GetVectorIntAsString(mInputSize)); + mInputDimLabel->setText(QString::number(mDimension)+"D"); + mInputSpacingLabel->setText(GetVectorDoubleAsString(mInputSpacing)); + mInputPixelTypeLabel->setText(mPixelType); + mInputMemoryLabel->setText(GetSizeInBytes(mInputSize)); + + // Set current size + scaleSizeRadioButton->setChecked(true); + UpdateControlSizeAndSpacing(); + scaleSizeLineEdit->setText("100"); + ComputeNewSizeFromScale(); + + // Update output + UpdateOutputInfo(); +} +//==================================================================== + +//==================================================================== +void vvResamplerDialog::UpdateOutputInfo() { + mOutputSizeLabel->setText(GetVectorIntAsString(mOutputSize)); + mOutputSpacingLabel->setText(GetVectorDoubleAsString(mOutputSpacing)); + mOutputMemoryLabel->setText(GetSizeInBytes(mOutputSize)); +} +//==================================================================== + +//==================================================================== +QString vvResamplerDialog::GetSizeInBytes(std::vector & size) { + int t = 1; + for (unsigned int i=0; iGetScalarSize()*mCurrentImage->GetNumberOfScalarComponents(); + QString result = QString::number(t); + result += " bytes ("; + if (t > 1000000000) { + t /= 1000000000; + result += QString::number(t); + result += " GB)"; + } + else if (t > 1000000) { + t /= 1000000; + result += QString::number(t); + result += " MB)"; + } + else if (t > 1000) { + t /= 1000; + result += QString::number(t); + result += " KB)"; + } + return result; +} +//==================================================================== + +//==================================================================== +QString vvResamplerDialog::GetVectorDoubleAsString(std::vector vectorDouble) { + QString result; + for (unsigned int i= 0; i vectorInt) { + QString result; + for (unsigned int i= 0; i size) { + xSizeLineEdit->setText(QString::number(size[0])); + ySizeLineEdit->setText(QString::number(size[1])); + if (size.size() > 2) + zSizeLineEdit->setText(QString::number(size[2])); +} +//==================================================================== + +//==================================================================== +void vvResamplerDialog::FillSpacingEdit(std::vector spacing) { + xSpacingLineEdit->setText(QString::number(spacing[0])); + ySpacingLineEdit->setText(QString::number(spacing[1])); + if (spacing.size() > 2) + zSpacingLineEdit->setText(QString::number(spacing[2])); +} +//==================================================================== + +//==================================================================== +void vvResamplerDialog::UpdateOutputSizeAndSpacing() { + mOutputSize.resize(mDimension); + mOutputSize = mInputSize; + mOutputSpacing.resize(mDimension); + mOutputSpacing = mInputSpacing; + mOutputSize[0] = (int)xSizeLineEdit->text().toDouble(); + mOutputSize[1] = (int)ySizeLineEdit->text().toDouble(); + if (mDimension > 2) + mOutputSize[2] = (int)zSizeLineEdit->text().toDouble(); + + mOutputSpacing[0] = xSpacingLineEdit->text().toDouble(); + mOutputSpacing[1] = ySpacingLineEdit->text().toDouble(); + if (mDimension > 2) + mOutputSpacing[2] = zSpacingLineEdit->text().toDouble(); + + UpdateOutputInfo(); +} +//==================================================================== + +//==================================================================== +void vvResamplerDialog::UpdateControlSizeAndSpacing() { + scaleSizeLineEdit->setText(""); + scaleSpacingLineEdit->setText(""); + isoSizeLineEdit->setText(""); + isoSpacingLineEdit->setText(""); + + xSizeLineEdit->setReadOnly(1); + ySizeLineEdit->setReadOnly(1); + zSizeLineEdit->setReadOnly(1); + scaleSizeLineEdit->setReadOnly(1); + isoSizeLineEdit->setReadOnly(1); + + xSpacingLineEdit->setReadOnly(1); + ySpacingLineEdit->setReadOnly(1); + zSpacingLineEdit->setReadOnly(1); + scaleSpacingLineEdit->setReadOnly(1); + isoSpacingLineEdit->setReadOnly(1); + + if (sizeRadioButton->isChecked()) { + xSizeLineEdit->setReadOnly(0); + ySizeLineEdit->setReadOnly(0); + if (mDimension > 2) + zSizeLineEdit->setReadOnly(0); + } + else { + if (spacingRadioButton->isChecked()) { + xSpacingLineEdit->setReadOnly(0); + ySpacingLineEdit->setReadOnly(0); + if (mDimension > 2) + zSpacingLineEdit->setReadOnly(0); + } + else if (scaleSizeRadioButton->isChecked()) + scaleSizeLineEdit->setReadOnly(0); + else if (scaleSpacingRadioButton->isChecked()) + scaleSpacingLineEdit->setReadOnly(0); + else if (isoSizeRadioButton->isChecked()) + isoSizeLineEdit->setReadOnly(0); + else if (isoSpacingRadioButton->isChecked()) + isoSpacingLineEdit->setReadOnly(0); + } +} +//==================================================================== + +//==================================================================== +void vvResamplerDialog::ComputeNewSpacingFromSize() { + double newSpacing = mInputSpacing[0]*mInputSize[0]; + xSpacingLineEdit->setText(QString::number(newSpacing/xSizeLineEdit->text().toDouble())); + newSpacing = mInputSpacing[1]*mInputSize[1]; + ySpacingLineEdit->setText(QString::number(newSpacing/ySizeLineEdit->text().toDouble())); + if (mDimension > 2) + { + newSpacing = mInputSpacing[2]*mInputSize[2]; + zSpacingLineEdit->setText(QString::number(newSpacing/zSizeLineEdit->text().toDouble())); + } + UpdateOutputSizeAndSpacing(); +} +//==================================================================== + +//==================================================================== +void vvResamplerDialog::ComputeNewSizeFromSpacing() { + double newSize = mInputSpacing[0]*mInputSize[0]; + xSizeLineEdit->setText(QString::number(newSize/xSpacingLineEdit->text().toDouble())); + newSize = mInputSpacing[1]*mInputSize[1]; + ySizeLineEdit->setText(QString::number(newSize/ySpacingLineEdit->text().toDouble())); + if (mDimension > 2) + { + newSize = mInputSpacing[2]*mInputSize[2]; + zSizeLineEdit->setText(QString::number(newSize/zSpacingLineEdit->text().toDouble())); + } + UpdateOutputSizeAndSpacing(); +} +//==================================================================== + +//==================================================================== +void vvResamplerDialog::ComputeNewSpacingFromScale() { + xSpacingLineEdit->setText(QString::number(mInputSpacing[0]*scaleSpacingLineEdit->text().toDouble()/100)); + ySpacingLineEdit->setText(QString::number(mInputSpacing[1]*scaleSpacingLineEdit->text().toDouble()/100)); + if (mDimension > 2) + zSpacingLineEdit->setText(QString::number(mInputSpacing[2]*scaleSpacingLineEdit->text().toDouble()/100)); + ComputeNewSizeFromSpacing(); +} +//==================================================================== + +//==================================================================== +void vvResamplerDialog::ComputeNewSizeFromScale() { + xSizeLineEdit->setText(QString::number(mInputSize[0]*scaleSizeLineEdit->text().toDouble()/100)); + ySizeLineEdit->setText(QString::number(mInputSize[1]*scaleSizeLineEdit->text().toDouble()/100)); + if (mDimension > 2) + zSizeLineEdit->setText(QString::number(mInputSize[2]*scaleSizeLineEdit->text().toDouble()/100)); + ComputeNewSpacingFromSize(); +} +//==================================================================== + +//==================================================================== +void vvResamplerDialog::ComputeNewSpacingFromIso() { + xSpacingLineEdit->setText(QString::number(isoSpacingLineEdit->text().toDouble())); + ySpacingLineEdit->setText(QString::number(isoSpacingLineEdit->text().toDouble())); + if (mDimension > 2) + zSpacingLineEdit->setText(QString::number(isoSpacingLineEdit->text().toDouble())); + ComputeNewSizeFromSpacing(); +} +//==================================================================== + +//==================================================================== +void vvResamplerDialog::ComputeNewSizeFromIso() { + xSizeLineEdit->setText(QString::number(isoSizeLineEdit->text().toDouble())); + ySizeLineEdit->setText(QString::number(isoSizeLineEdit->text().toDouble())); + if (mDimension > 2) + zSizeLineEdit->setText(QString::number(isoSizeLineEdit->text().toDouble())); + ComputeNewSpacingFromSize(); +} +//==================================================================== + +//==================================================================== +void vvResamplerDialog::UpdateInterpolation() { + if (interpolationComboBox->currentText() == "BSpline") { + bSplineLabel->show(); + bSplineOrderSpinBox->show(); + bLUTFactorLabel->hide(); + bLUTSpinBox->hide(); + } + else if (interpolationComboBox->currentText() == "Blut (faster BSpline)") { + bSplineLabel->show(); + bSplineOrderSpinBox->show(); + bLUTFactorLabel->show(); + bLUTSpinBox->show(); + } + else { + bSplineLabel->hide(); + bSplineOrderSpinBox->hide(); + bLUTFactorLabel->hide(); + bLUTSpinBox->hide(); + } +} +//==================================================================== + +//==================================================================== +void vvResamplerDialog::UpdateGaussianFilter() { + if (gaussianFilterCheckBox->isChecked()) { + gaussianFilterLabel->show(); + xGaussianLineEdit->show(); + yGaussianLineEdit->show(); + if (mDimension > 2) + zGaussianLineEdit->show(); + } + else { + gaussianFilterLabel->hide(); + xGaussianLineEdit->hide(); + yGaussianLineEdit->hide(); + zGaussianLineEdit->hide(); + } +} +//==================================================================== + +//==================================================================== +void vvResamplerDialog::SetSlicerManagers(std::vector & m,int current_image_index) { + mSlicerManagers = m; + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) { + mImagesComboBox->addItem(mSlicerManagers[i]->GetFileName().c_str()); + } + mImagesComboBox->setCurrentIndex(current_image_index); +} +//==================================================================== + +//==================================================================== +void vvResamplerDialog::Resample() { + + // Get resampler options + std::vector sigma; + sigma.push_back(xGaussianLineEdit->text().toDouble()); + sigma.push_back(yGaussianLineEdit->text().toDouble()); + if (mDimension > 2) sigma.push_back(zGaussianLineEdit->text().toDouble()); + + + // Create resampler filter + clitk::ImageResampleGenericFilter::Pointer filter = clitk::ImageResampleGenericFilter::New(); + filter->SetOutputSize(mOutputSize); + filter->SetOutputSpacing(mOutputSpacing); + filter->SetInterpolationName(interpolationComboBox->currentText().toLower().toStdString()); + + if (interpolationComboBox->currentText() == "BSpline") + filter->SetBSplineOrder(bSplineOrderSpinBox->value()); + else if (interpolationComboBox->currentText() == "Blut (faster BSpline)") { + filter->SetInterpolationName("blut"); + filter->SetBSplineOrder(bSplineOrderSpinBox->value()); + filter->SetBLUTSampling(bLUTSpinBox->value()); + } + if (gaussianFilterCheckBox->isChecked()) + filter->SetGaussianSigma(sigma); + // filter->SetOutputFileName(OutputFileName.toStdString()); + filter->SetDefaultPixelValue(defaultPixelValueLineEdit->text().toDouble()); + filter->SetInputVVImage(mCurrentImage); + + // Go ! + filter->Update(); + mOutput = filter->GetOutputVVImage(); +} +//==================================================================== +std::string vvResamplerDialog::GetOutputFileName() +{ + QFileInfo info(mImagesComboBox->currentText()); + return (info.path().toStdString() + "/resampled_" + info.fileName().toStdString()); +} + +#endif /* end #define _vvResamplerDialog_CXX */ + diff --git a/vv/vvResamplerDialog.h b/vv/vvResamplerDialog.h new file mode 100644 index 0000000..5d68eb6 --- /dev/null +++ b/vv/vvResamplerDialog.h @@ -0,0 +1,114 @@ +#ifndef _VVRESAMPLERDIALOG_H +#define _VVRESAMPLERDIALOG_H + +/*========================================================================= + +Program: vv +Module: $RCSfile: vvResamplerDialog.h,v $ +Language: C++ +Date: $Date: 2010/01/06 13:31:57 $ +Version: $Revision: 1.1 $ +Author : David Sarrut (david.sarrut@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + + +#include "ui_vvResamplerDialog.h" +#include "clitkCommon.h" +#include "vvImage.h" +#include "vvSlicerManager.h" + +#include +#include + +//==================================================================== +class QDESIGNER_WIDGET_EXPORT vvResamplerDialog : public QDialog, private Ui::vvResamplerDialog { + + Q_OBJECT + +public: + // constructor - destructor + vvResamplerDialog(QWidget * parent=0, Qt::WindowFlags f=0); + void SetSlicerManagers(std::vector & m,int current_image_index); + + // Get output result + vvImage::Pointer GetOutput() { + return mOutput; + } + bool GetDisplayResult() { + return display_result->checkState() > 0; + } + std::string GetOutputFileName(); + +public slots: +// void SetImagesList(QTreeWidget * tree); + void Resample(); + void UpdateControlSizeAndSpacing(); + void ComputeNewSizeFromSpacing(); + void ComputeNewSizeFromScale(); + void ComputeNewSizeFromIso(); + void ComputeNewSpacingFromSize(); + void ComputeNewSpacingFromScale(); + void ComputeNewSpacingFromIso(); + void UpdateInterpolation(); + void UpdateGaussianFilter(); + void UpdateCurrentInputImage(); + +protected: + Ui::vvResamplerDialog ui; + std::vector mSlicerManagers; + vvImage::Pointer mOutput; + + vvImage::Pointer mCurrentImage; + int mCurrentIndex; + + std::vector mInputOrigin; + std::vector mInputSize; + std::vector mInputSpacing; + std::vector mOutputSize; + std::vector mOutputSpacing; + int mDimension; + + QString mLastError; + + QString mInputFileName; + + QString mInputFileFormat; + QString mPixelType; + QString ComponentType; + + QStringList OutputListFormat; + + void Init(); + void UpdateInputInfo(); + void UpdateOutputInfo(); + void UpdateOutputFormat(); + void FillSizeEdit(std::vector size); + void FillSpacingEdit(std::vector spacing); + void UpdateOutputSizeAndSpacing(); + + QString GetSizeInBytes(std::vector & size); + QString GetVectorDoubleAsString(std::vector vectorDouble); + QString GetVectorIntAsString(std::vector vectorInt); + +}; // end class vvResamplerDialog +//==================================================================== + +#endif /* end #define _VVRESAMPLERDIALOG_H */ + diff --git a/vv/vvSegmentationDialog.cxx b/vv/vvSegmentationDialog.cxx new file mode 100644 index 0000000..bee3327 --- /dev/null +++ b/vv/vvSegmentationDialog.cxx @@ -0,0 +1,626 @@ +#ifndef _vvSegmentationDialog_CXX +#define _vvSegmentationDialog_CXX + +/*========================================================================= + +Program: vv +Module: $RCSfile: vvSegmentationDialog.cxx,v $ +Language: C++ +Date: $Date: 2010/01/06 13:31:58 $ +Version: $Revision: 1.1 $ +Author : David Sarrut (david.sarrut@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#include +#include + +#include "vvSegmentationDialog.h" +#include "vvProgressDialog.h" +#include "vvImageWriter.h" +#include "vvLandmarks.h" +#include "vvInteractorStyleNavigator.h" +#include "vvSlicer.h" + +#include "vtkMarchingCubes.h" +#include "vtkMarchingSquares.h" +#include "vtkImageClip.h" +#include "vtkCamera.h" +#include "vtkRenderer.h" +#include "vtkProperty.h" +#include "vtkLookupTable.h" +#include "vtkClipPolyData.h" +#include "vtkImageToPolyDataFilter.h" +#include "vtkLookupTable.h" +#include "vtkDoubleArray.h" +#include "vtkPointData.h" +#include "vtkCellData.h" +#include "vtkImageMapToWindowLevelColors.h" +#include "vtkImageContinuousErode3D.h" +#include "vtkImageContinuousDilate3D.h" +#include "vtkImageLogic.h" +#include "vtkInteractorStyleTrackballCamera.h" +#include "vtkImageSeedConnectivity.h" +#include "vtkConnectivityFilter.h" +#include "vtkPolyData.h" +#include +#include +#include "vtkInformation.h" +#include "vtkInformationVector.h" +#include "vtkStreamingDemandDrivenPipeline.h" +#include + +#include + +//==================================================================== +vvSegmentationDialog::vvSegmentationDialog(QWidget * parent, Qt::WindowFlags f) + :QDialog(parent,f), Ui::vvSegmentationDialog() { + + // initialization + setupUi(this); + mManager = new vvSlicerManager(1); + + mClipper = vtkImageClip::New(); + mSquares1 = vtkMarchingSquares::New(); + mSquaresMapper1 = vtkPolyDataMapper::New(); + mSquaresActor1 = vtkActor::New(); + + mSquares2 = vtkMarchingSquares::New(); + mSquaresMapper2 = vtkPolyDataMapper::New(); + mSquaresActor2 = vtkActor::New(); + + //m3DMapper = vtkPolyDataMapper::New(); + //m3DActor = vtkActor::New(); + m3DExtractor = vtkMarchingCubes::New(); + m3DMappers.clear(); + m3DActors.clear(); + + mBinaireImages.clear(); + mKernelValue = 2; + + connect(clipping1Slider,SIGNAL(valueChanged(int)),this,SLOT(clippingvaluechanged(int))); + connect(clipping2Slider,SIGNAL(valueChanged(int)),this,SLOT(clippingvaluechanged(int))); + connect(binaryButton,SIGNAL(clicked()),this,SLOT(BinariseSurface())); + connect(saveButton,SIGNAL(clicked()),this,SLOT(Save())); + connect(erodeButton,SIGNAL(clicked()),this,SLOT(Erode())); + connect(dilateButton,SIGNAL(clicked()),this,SLOT(Dilate())); + connect(dimButton,SIGNAL(clicked()),this,SLOT(ChangeDimRendering())); + connect(kernelSpinBox,SIGNAL(valueChanged(int)),this,SLOT(KernelValueChanged(int))); + + binaryButton->setEnabled(0); + erodeButton->setEnabled(0); + dilateButton->setEnabled(0); + infoLabel->setText("Select Up and Down threshold before clicking binarise !"); +} + +vvSegmentationDialog::~vvSegmentationDialog() +{ + mClipper->Delete(); + + mSquaresActor1->Delete(); + mSquaresMapper1->Delete(); + mSquares1->Delete(); + + mSquaresActor2->Delete(); + mSquaresMapper2->Delete(); + mSquares2->Delete(); + + //m3DMapper->Delete(); + //m3DActor->Delete(); + m3DExtractor->Delete(); + + for (unsigned int i = 0; i < mBinaireImages.size(); i++) + mBinaireImages[i]->Delete(); + + for (unsigned int i = 0; i < m3DActors.size(); i++) + m3DActors[i]->Delete(); + + for (unsigned int i = 0; i < m3DMappers.size(); i++) + m3DMappers[i]->Delete(); + + delete mManager; +} + +//---------------------------------------------------------------------------- +// This templated function executes the filter for any type of data. +// Handles the one input operations +template +void vvImageBinarize(vtkImageData *in1Data, T *in1Ptr, + int outExt[6],int clampMin, int clampMax) +{ + int idxR, idxY, idxZ; + int maxY, maxZ; + vtkIdType inIncX, inIncY, inIncZ; + int rowLength; + + // find the region to loop over + rowLength = + (outExt[1] - outExt[0]+1)*in1Data->GetNumberOfScalarComponents(); + // What a pain. Maybe I should just make another filter. + + maxY = outExt[3] - outExt[2]; + maxZ = outExt[5] - outExt[4]; + + // Get increments to march through data + in1Data->GetContinuousIncrements(outExt, inIncX, inIncY, inIncZ); + + for (idxZ = 0; idxZ <= maxZ; idxZ++) + { + for (idxY = 0; idxY <= maxY; idxY++) + { + for (idxR = 0; idxR < rowLength; idxR++) + { + if (static_cast(*in1Ptr) > clampMin && static_cast(*in1Ptr) <= clampMax) + *in1Ptr = static_cast(1); + else + *in1Ptr = static_cast(0); + in1Ptr++; + } + in1Ptr += inIncY; + } + in1Ptr += inIncZ; + } +} + +void vvSegmentationDialog::SetImage(vvImage::Pointer image) +{ + + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + mManager->SetImage(image); + mManager->SetSlicerWindow(0,viewWidget->GetRenderWindow()); + vvInteractorStyleNavigator* style = vvInteractorStyleNavigator::New(); + mManager->SetInteractorStyleNavigator(0,style); + style->Delete(); + + double range[2]; + mManager->GetImage()->GetScalarRange(range); + mManager->GetSlicer(0)->SetColorWindow(range[1]-range[0]); + mManager->GetSlicer(0)->SetColorLevel((range[1]+range[0])/2); + + clipping1Slider->setMinimum(range[0]); + clipping1Slider->setMaximum(range[1]); + clipping2Slider->setMinimum(range[0]); + clipping2Slider->setMaximum(range[1]); + clipping1Slider->setValue(range[0]); + clipping2Slider->setValue(range[1]); + + mClipper->SetInput(mManager->GetSlicer(0)->GetInput()); + mSquares1->SetValue(0,clipping1Slider->value()); + mSquares2->SetValue(0,clipping2Slider->value()); + mSquares1->SetInput(mClipper->GetOutput()); + mSquares2->SetInput(mClipper->GetOutput()); + + mSquaresMapper1->SetInput(mSquares1->GetOutput()); + mSquaresMapper2->SetInput(mSquares2->GetOutput()); + mSquaresMapper1->ScalarVisibilityOff(); + mSquaresMapper2->ScalarVisibilityOff(); + + mSquaresActor1->SetMapper(mSquaresMapper1); + mSquaresActor2->SetMapper(mSquaresMapper2); + mSquaresActor1->GetProperty()->SetColor(1.0,0,0); + mSquaresActor2->GetProperty()->SetColor(0,0,1.0); + mSquaresActor1->SetPickable(0); + mSquaresActor2->SetPickable(0); + + mManager->GetSlicer(0)->GetRenderer()->AddActor(mSquaresActor1); + mManager->GetSlicer(0)->GetRenderer()->AddActor(mSquaresActor2); + + mSquares1->Update(); + mSquares2->Update(); + + UpdateSlice(0,mManager->GetSlicer(0)->GetSlice()); + + connect(mManager,SIGNAL(UpdateTSlice(int,int)),this,SLOT(UpdateSlice(int, int))); + connect(mManager,SIGNAL(UpdateSlice(int,int)),this,SLOT(UpdateSlice(int, int))); + connect(mManager,SIGNAL(UpdateSliceRange(int,int,int,int,int)),this,SLOT(UpdateSlice(int, int))); + connect(mManager,SIGNAL(LandmarkAdded()),this,SLOT(InsertSeed())); + QApplication::restoreOverrideCursor(); +} + +void vvSegmentationDialog::UpdateSlice(int slicer,int slices) +{ + int slice = mManager->GetSlicer(0)->GetSlice(); + int tslice = mManager->GetSlicer(0)->GetTSlice(); + mClipper->SetInput(mManager->GetSlicer(0)->GetInput()); + int* extent = mManager->GetSlicer(0)->GetImageActor()->GetDisplayExtent(); + mClipper->SetOutputWholeExtent(extent[0],extent[1],extent[2],extent[3],extent[4],extent[5]); + int i; + for (i = 0; i < 6;i = i+2) + { + if (extent[i] == extent[i+1]) + { + break; + } + } + + switch (i) + { + case 0: + if (mManager->GetSlicer(0)->GetRenderer()->GetActiveCamera()->GetPosition()[0] > slice) + { + mSquaresActor1->SetPosition(1,0,0); + mSquaresActor2->SetPosition(1,0,0); + } + else + { + mSquaresActor1->SetPosition(-1,0,0); + mSquaresActor2->SetPosition(-1,0,0); + } + break; + case 2: + if (mManager->GetSlicer(0)->GetRenderer()->GetActiveCamera()->GetPosition()[1] > slice) + { + mSquaresActor1->SetPosition(0,1,0); + mSquaresActor2->SetPosition(0,1,0); + } + else + { + mSquaresActor1->SetPosition(0,-1,0); + mSquaresActor2->SetPosition(0,-1,0); + } + break; + case 4: + if (mManager->GetSlicer(0)->GetRenderer()->GetActiveCamera()->GetPosition()[2] > slice) + { + mSquaresActor1->SetPosition(0,0,1); + mSquaresActor2->SetPosition(0,0,1); + } + else + { + mSquaresActor1->SetPosition(0,0,-1); + mSquaresActor2->SetPosition(0,0,-1); + } + break; + } + mSquares1->Update(); + mSquares2->Update(); + + if (m3DActors.size()) + { + for (unsigned int i =0; i < m3DActors.size(); i++) + { + if (m3DActors[i]->GetVisibility()) + { + m3DActors[i]->VisibilityOff(); + } + } + std::cout << "display " << tslice << " on " << m3DActors.size() << std::endl; + m3DActors[tslice]->VisibilityOn(); + } + + mManager->Render(); +} + + +void vvSegmentationDialog::clippingvaluechanged(int value) +{ + binaryButton->setEnabled(1); + int min = (clipping1Slider->value() < clipping2Slider->value() ) ? + clipping1Slider->value():clipping2Slider->value(); + int max = (clipping1Slider->value() > clipping2Slider->value() ) ? + clipping1Slider->value():clipping2Slider->value(); + mSquares1->SetValue(0,min); + mSquares2->SetValue(0,max); + + QString textMin = " Min : "; + textMin += QString::number(min); + QString textMax = "\n Max : "; + textMax += QString::number(max); + minLabel->setText(textMin); + maxLabel->setText(textMax); + + if (mSquares1->GetInput()) + { + mSquares1->Update(); + mSquares2->Update(); + mManager->Render(); + } +} + + +void vvSegmentationDialog::BinariseSurface() +{ + infoLabel->setText("Click erode then space on desired organ !"); + + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + int clampMin = (clipping1Slider->value() < clipping2Slider->value() ) ? + clipping1Slider->value():clipping2Slider->value(); + int clampMax = (clipping1Slider->value() > clipping2Slider->value() ) ? + clipping1Slider->value():clipping2Slider->value(); + vtkImageData* outputImage = vtkImageData::New(); + + for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++) + { + vtkImageData* image = mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage]; + int ext[6]; + image->GetWholeExtent(ext); + void *in1Ptr; + in1Ptr = image->GetScalarPointerForExtent(ext); + + switch (image->GetScalarType()) + { + vtkTemplateMacro( + vvImageBinarize(image, static_cast(in1Ptr), + ext,clampMin,clampMax)); + default: + std::cerr << "Error, unknown pixel format : " << image->GetScalarTypeAsString() << std::endl; + return; + } + + outputImage->Initialize(); + outputImage->SetExtent(ext); + outputImage->SetOrigin(image->GetOrigin()); + outputImage->SetSpacing(image->GetSpacing()); + outputImage->SetScalarTypeToUnsignedChar(); + outputImage->CopyAndCastFrom(image,ext); + outputImage->Update(); + + image->DeepCopy(outputImage); + image->UpdateInformation(); + image->PropagateUpdateExtent(); + + vtkImageData* imageBin = vtkImageData::New(); + imageBin->DeepCopy(image); + imageBin->Update(); + mBinaireImages.push_back(imageBin); + } + + outputImage->Delete(); + erodeButton->setEnabled(1); + QApplication::restoreOverrideCursor(); + mManager->SetColorWindow(2); + mManager->SetColorLevel(0.5); + mManager->Render(); +} + +void vvSegmentationDialog::Erode() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + vtkImageContinuousErode3D* erode = vtkImageContinuousErode3D::New(); + erode->SetKernelSize(mKernelValue,mKernelValue,mKernelValue); + for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++) + { + vtkImageData* image = mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage]; + erode->SetInput(image); + erode->Update(); + image->DeepCopy(erode->GetOutput()); + image->Update(); + } + erode->Delete(); + dilateButton->setEnabled(1); + mManager->Render(); + QApplication::restoreOverrideCursor(); +} + +void vvSegmentationDialog::Dilate() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + vtkImageContinuousDilate3D* dilate = vtkImageContinuousDilate3D::New(); + vtkImageLogic* And = vtkImageLogic::New(); + And->SetOperationToAnd(); + dilate->SetKernelSize(mKernelValue,mKernelValue,mKernelValue); + for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++) + { + vtkImageData* image = mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage]; + dilate->SetInput(image); + vtkImageData* mask = mBinaireImages[numImage]; + And->SetInput1(dilate->GetOutput()); + And->SetInput2(mask); + And->Update(); + image->DeepCopy(And->GetOutput()); + image->Update(); + } + And->Delete(); + dilate->Delete(); + mManager->Render(); + QApplication::restoreOverrideCursor(); +} + +void vvSegmentationDialog::InsertSeed() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + int point4D[4]; + point4D[0] = mManager->GetLandmarks()->GetCoordinates( + mManager->GetLandmarks()->GetNumberOfPoints()-1)[0]; + point4D[1] = mManager->GetLandmarks()->GetCoordinates( + mManager->GetLandmarks()->GetNumberOfPoints()-1)[1]; + point4D[2] = mManager->GetLandmarks()->GetCoordinates( + mManager->GetLandmarks()->GetNumberOfPoints()-1)[2]; + point4D[3] = mManager->GetLandmarks()->GetCoordinates( + mManager->GetLandmarks()->GetNumberOfPoints()-1)[3]; + + point4D[0] = point4D[0]/mManager->GetSlicer(0)->GetImage()->GetVTKImages()[0]->GetSpacing()[0]; + point4D[1] = point4D[1]/mManager->GetSlicer(0)->GetImage()->GetVTKImages()[0]->GetSpacing()[1]; + point4D[2] = point4D[2]/mManager->GetSlicer(0)->GetImage()->GetVTKImages()[0]->GetSpacing()[2]; + + vtkImageSeedConnectivity* seed = vtkImageSeedConnectivity::New(); + seed->SetInputConnectValue(1); + seed->SetOutputConnectedValue(1); + seed->SetOutputUnconnectedValue(0); + seed->AddSeed(point4D[0],point4D[1],point4D[2]); + + for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++) + { + vtkImageData* image = mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage]; + seed->SetInput(image); + seed->Update(); + image->DeepCopy(seed->GetOutput()); + image->Update(); + } + + seed->Delete(); + QApplication::restoreOverrideCursor(); +} + +void vvSegmentationDialog::ChangeDimRendering() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + + if (dimButton->text() == "3D") + { + if (m3DActors.size() == 0) + { + m3DExtractor->SetValue(0,0.5); + for (unsigned int numImage = 0; numImage < mManager->GetSlicer(0)->GetImage()->GetVTKImages().size(); numImage++) + { + vtkActor* actor = vtkActor::New(); + m3DExtractor->SetInput(mManager->GetSlicer(0)->GetImage()->GetVTKImages()[numImage]); + m3DExtractor->Update(); + + vtkPolyDataMapper* mapper = vtkPolyDataMapper::New(); + mapper->SetInput(m3DExtractor->GetOutput()); + m3DMappers.push_back(mapper); + + actor->SetMapper(mapper); + actor->GetProperty()->SetColor(1.0,0.7,0.2); + actor->VisibilityOff(); + + mManager->GetSlicer(0)->GetRenderer()->AddActor(actor); + m3DActors.push_back(actor); + } + } + + mManager->GetSlicer(0)->GetRenderer()->SetBackground(0.5,0.6,0.9); + m3DActors[0]->VisibilityOn(); + + vtkInteractorStyleTrackballCamera* style = vtkInteractorStyleTrackballCamera::New(); + mManager->SetInteractorStyleNavigator(0,style); + style->Delete(); + + mManager->GetSlicer(0)->GetImageActor()->VisibilityOff(); + mSquaresActor1->VisibilityOff(); + mSquaresActor2->VisibilityOff(); + mManager->Render(); + dimButton->setText("2D"); + } + else + { + mManager->GetSlicer(0)->GetRenderer()->SetBackground(0.0,0.0,0.0); + vvInteractorStyleNavigator* style = vvInteractorStyleNavigator::New(); + mManager->SetInteractorStyleNavigator(0,style); + style->Delete(); + + mManager->GetSlicer(0)->SetSliceOrientation(2); + m3DActors[mManager->GetSlicer(0)->GetTSlice()]->VisibilityOff(); + + mManager->GetSlicer(0)->GetImageActor()->VisibilityOn(); + mSquaresActor1->VisibilityOn(); + mSquaresActor2->VisibilityOn(); + dimButton->setText("3D"); + } + QApplication::restoreOverrideCursor(); +} + +void vvSegmentationDialog::KernelValueChanged(int kernel) +{ + mKernelValue = kernel; +} + +void vvSegmentationDialog::Save() +{ + if (dimButton->text() == "2D") //If in *3D* mode, save the mesh + { + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save Mesh As"), + QDir::home().dirName(), + "Mesh Files (*.vtk *.vtp)"); + if (!fileName.isEmpty()) + { + vtkSmartPointer w = vtkSmartPointer::New(); + w->SetInput(m3DExtractor->GetOutput()); + w->SetFileName(fileName.toStdString().c_str()); + w->Write(); + } + } + else { + QStringList OutputListeFormat; + OutputListeFormat.clear(); + int dimension = mManager->GetDimension(); + if (dimension == 1) + { + OutputListeFormat.push_back(".mhd"); + } + if (dimension == 2) + { + OutputListeFormat.push_back(".bmp"); + OutputListeFormat.push_back(".png"); + OutputListeFormat.push_back(".jpeg"); + OutputListeFormat.push_back(".tif"); + OutputListeFormat.push_back(".mhd"); + OutputListeFormat.push_back(".hdr"); + OutputListeFormat.push_back(".vox"); + } + else if (dimension == 3) + { + OutputListeFormat.push_back(".mhd"); + OutputListeFormat.push_back(".hdr"); + OutputListeFormat.push_back(".vox"); + } + else if (dimension == 4) + { + OutputListeFormat.push_back(".mhd"); + } + QString Extensions = "AllFiles(*.*)"; + for (int i = 0; i < OutputListeFormat.count(); i++) + { + Extensions += ";;Images ( *"; + Extensions += OutputListeFormat[i]; + Extensions += ")"; + } + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save As"), + QDir::home().dirName(), + Extensions); + if (!fileName.isEmpty()) + { + std::string fileformat = vtksys::SystemTools::GetFilenameLastExtension(fileName.toStdString()); + if (OutputListeFormat.contains( + fileformat.c_str())) + { + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + vvProgressDialog progress("Saving "+fileName.toStdString()); + qApp->processEvents(); + vvImageWriter *writer = new vvImageWriter; + writer->SetOutputFileName(fileName.toStdString()); + writer->SetInput(mManager->GetSlicer(0)->GetImage()); + writer->Update(dimension,"unsigned_char"); + QApplication::restoreOverrideCursor(); + if (writer->GetLastError().size()) + { + QString error = "Saving did not succeed\n"; + error += writer->GetLastError().c_str(); + QMessageBox::information(this,tr("Saving Problem"),error); + Save(); + } + } + else + { + QString error = fileformat.c_str(); + if (error.isEmpty()) + error += "no file format specified !"; + else + error += " format unknown !!!\n"; + QMessageBox::information(this,tr("Saving Problem"),error); + Save(); + } + } + } +} + +#endif /* end #define _vvSegmentationDialog_CXX */ + diff --git a/vv/vvSegmentationDialog.h b/vv/vvSegmentationDialog.h new file mode 100644 index 0000000..784eb3d --- /dev/null +++ b/vv/vvSegmentationDialog.h @@ -0,0 +1,99 @@ +#ifndef _VVSEGMENTATIONDIALOG_H +#define _VVSEGMENTATIONDIALOG_H + +/*========================================================================= + +Program: vv +Module: $RCSfile: vvSegmentationDialog.h,v $ +Language: C++ +Date: $Date: 2010/01/06 13:31:58 $ +Version: $Revision: 1.1 $ +Author : David Sarrut (david.sarrut@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + + +#include "ui_vvSegmentationDialog.h" +#include "clitkCommon.h" +#include "vvImage.h" +#include "vvSlicerManager.h" +#include "vtkMarchingSquares.h" +#include "vtkImageClip.h" +#include "vtkClipPolyData.h" +#include "vtkImageToPolyDataFilter.h" +#include "vtkLookupTable.h" +#include "vtkImageMapToWindowLevelColors.h" +#include "vtkImageActor.h" +#include "vtkMarchingCubes.h" +#include "vtkPolyData.h" +#include + +#include +#include + +//==================================================================== +class vvSegmentationDialog : public QDialog, private Ui::vvSegmentationDialog { + + Q_OBJECT + +public: + // constructor - destructor + vvSegmentationDialog(QWidget * parent=0, Qt::WindowFlags f=0); + ~vvSegmentationDialog(); + void SetImage(vvImage::Pointer image); + +public slots: + void clippingvaluechanged(int); + void UpdateSlice(int slicer,int slice); + void BinariseSurface(); + void Erode(); + void Dilate(); + void Save(); + void ChangeDimRendering(); + void InsertSeed(); + void KernelValueChanged(int kernel); + +protected: + Ui::vvSegmentationDialog ui; + + vvSlicerManager* mManager; + + vtkImageClip* mClipper; + + vtkMarchingSquares* mSquares1; + vtkPolyDataMapper* mSquaresMapper1; + vtkActor* mSquaresActor1; + + vtkMarchingSquares* mSquares2; + vtkPolyDataMapper* mSquaresMapper2; + vtkActor* mSquaresActor2; + + std::vector m3DMappers; + //vtkActor* m3DActor; + vtkMarchingCubes* m3DExtractor; + std::vector m3DActors; + + int mKernelValue; + + std::vector mBinaireImages; + +}; // end class vvSegmentationDialog +//==================================================================== + +#endif /* end #define _VVSEGMENTATIONDIALOG_H */ diff --git a/vv/vvSlicer.cxx b/vv/vvSlicer.cxx new file mode 100644 index 0000000..64df64c --- /dev/null +++ b/vv/vvSlicer.cxx @@ -0,0 +1,1185 @@ +/*========================================================================= + +Program: vv +Module: $RCSfile: vvSlicer.cxx,v $ +Language: C++ +Date: $Date: 2010/01/06 13:31:58 $ +Version: $Revision: 1.1 $ +Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#include "vvSlicer.h" + +#include "vvImage.h" +#include "vvImage.h" +#include "vvSlicerManagerCommand.h" +#include "vvGlyphSource.h" +#include "vvGlyph2D.h" +#include "vvImageMapToWLColors.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +vtkCxxRevisionMacro(vvSlicer, "$Revision: 1.1 $"); +vtkStandardNewMacro(vvSlicer); + +vvSlicer::vvSlicer() +{ + mImage = NULL; + mCurrentTSlice = 0; + + mCurrent[0] = -VTK_DOUBLE_MAX; + mCurrent[1] = -VTK_DOUBLE_MAX; + mCurrent[2] = -VTK_DOUBLE_MAX; + + mCursor[0] = -VTK_DOUBLE_MAX; + mCursor[1] = -VTK_DOUBLE_MAX; + mCursor[2] = -VTK_DOUBLE_MAX; + mCursor[3] = -VTK_DOUBLE_MAX; + + mSubSampling = 5; + mScale = 1; + mVFLog = 0; + + std::string text = "F1 = sagital; F2 = coronal; F3 = axial\n"; + text += "F5 = horizontal flip; F6 = vertical flip\n\n"; + text += "0,1,2,3,4,5 : preset windowing\n"; + text += "6,7,8,9 : preset colormap\n"; + text += "r : reset view\n"; + text += "l : reload image\n"; + text += "f : fly to mouse position\n"; + text += "g : go to cross hair position\n\n"; + text += "Up,down : change slice\n"; + text += "Left,right : change tenporal slice\n\n"; + text += "Scrollbar (or w/x) : zoom in/out\n"; + text += "left button : synchronize all views\n"; + text += "middle button : grab image\n"; + text += "right button : change windowing\n"; + + crossCursor = vtkCursor2D::New(); + crossCursor->AllOff(); + crossCursor->AxesOn(); + crossCursor->SetTranslationMode(1); + crossCursor->SetRadius(2); + + pdm = vtkPolyDataMapper2D::New(); + pdm->SetInput(crossCursor->GetOutput()); + + pdmA = vtkActor2D::New(); + pdmA->SetMapper(pdm); + pdmA->GetProperty()->SetColor(255,10,212); + pdmA->SetVisibility(0); + pdmA->SetPickable(0); + + ca = vtkCornerAnnotation::New(); + ca->GetTextProperty()->SetColor(255,10,212); + ca->SetVisibility(1); + mFileName = ""; + + mVF = NULL; + mOverlay = NULL; + mFusion = NULL; + mLandmarks = NULL; + + legend = vtkSmartPointer::New(); + //legend->SetTitle("test!"); + legend->SetPosition(0.82,0.18); + legend->SetWidth(0.1); + legend->SetVisibility(0); + legend->SetLabelFormat("%.1f"); + this->GetRenderer()->AddActor(legend); + + this->WindowLevel->Delete(); + this->WindowLevel = vvImageMapToWLColors::New(); + this->InstallPipeline(); +} + +vtkImageMapToWindowLevelColors* vvSlicer::GetOverlayMapper() { + return mOverlayMapper.GetPointer(); +} +vtkImageActor* vvSlicer::GetOverlayActor() { + return mOverlayActor.GetPointer(); +} +vtkImageMapToWindowLevelColors* vvSlicer::GetFusionMapper() { + return mFusionMapper.GetPointer(); +} + +vtkImageActor* vvSlicer::GetFusionActor() { + return mFusionActor.GetPointer(); +} +vtkActor* vvSlicer::GetVFActor() { + return mVFActor.GetPointer(); +} +vtkCornerAnnotation* vvSlicer::GetAnnotation() { + return ca.GetPointer(); +} + +void vvSlicer::AddContour(vvMesh::Pointer contour,bool propagate) +{ + + mSurfaceCutActors.push_back(new vvMeshActor()); + if (propagate) + mSurfaceCutActors.back()->Init(contour,mCurrentTSlice,mVF); + else + mSurfaceCutActors.back()->Init(contour,mCurrentTSlice); + mSurfaceCutActors.back()->SetSlicingOrientation(SliceOrientation); + this->GetRenderer()->AddActor(mSurfaceCutActors.back()->GetActor()); + + SetContourSlice(); +} + +void vvSlicer::ToggleContourSuperposition() +{ + for (std::vector::iterator i=mSurfaceCutActors.begin(); + i!=mSurfaceCutActors.end();i++) + (*i)->ToggleSuperposition(); +} + +void vvSlicer::SetCursorColor(int r,int g, int b) +{ + pdmA->GetProperty()->SetColor(r,g,b); +} +void vvSlicer::SetCursorVisibility(bool s) +{ + pdmA->SetVisibility(s); +} +bool vvSlicer::GetCursorVisibility() +{ + return pdmA->GetVisibility(); +} + +vvSlicer::~vvSlicer() +{ + for (std::vector::iterator i=mSurfaceCutActors.begin(); + i!=mSurfaceCutActors.end();i++) + delete (*i); +} + +void vvSlicer::SetCurrentPosition(double x, double y, double z, int t) +{ + mCurrent[0] = x; + mCurrent[1] = y; + mCurrent[2] = z; + mCurrentTSlice = t; +} + +void vvSlicer::SetImage(vvImage::Pointer image) +{ + if (image->GetVTKImages().size()) + { + mImage = image; + this->Superclass::SetInput(image->GetVTKImages()[0]); + this->UpdateDisplayExtent(); + mCurrentTSlice = 0; + ca->SetText(0,mFileName.c_str()); + } +} + +void vvSlicer::SetOverlay(vvImage::Pointer overlay) +{ + if (overlay->GetVTKImages().size()) + { + mOverlay = overlay; + + if (!mOverlayMapper) + mOverlayMapper = vtkImageMapToWindowLevelColors::New(); + mOverlayMapper->SetInput(overlay->GetVTKImages()[0]); + + if (!mOverlayActor) + mOverlayActor = vtkImageActor::New(); + mOverlayActor->SetInput(mOverlayMapper->GetOutput()); + mOverlayActor->SetPickable(0); + mOverlayActor->SetVisibility(false); + mOverlayActor->SetOpacity(0.5); + this->UpdateDisplayExtent(); + + //stupid but necessary : the Overlay need to be render before fusion + if (mFusionActor) + { + this->GetRenderer()->RemoveActor(mFusionActor); + this->GetRenderer()->AddActor(mOverlayActor); + this->GetRenderer()->AddActor(mFusionActor); + } + else + this->GetRenderer()->AddActor(mOverlayActor); + + //Synchronize slice + SetTSlice(mCurrentTSlice); + } +} + +void vvSlicer::SetFusion(vvImage::Pointer fusion) +{ + if (fusion->GetVTKImages().size()) + { + mFusion = fusion; + + if (!mFusionMapper) + mFusionMapper = vtkImageMapToWindowLevelColors::New(); + mFusionMapper->SetInput(fusion->GetVTKImages()[0]); + + if (!mFusionActor) + mFusionActor = vtkImageActor::New(); + mFusionActor->SetInput(mFusionMapper->GetOutput()); + mFusionActor->SetPickable(0); + mFusionActor->SetVisibility(false); + mFusionActor->SetOpacity(0.7); + this->UpdateDisplayExtent(); + this->GetRenderer()->AddActor(mFusionActor); + + //Synchronize slice + SetTSlice(mCurrentTSlice); + } +} + +void vvSlicer::SetActorVisibility(const std::string& actor_type, int overlay_index ,bool vis) +{ + if (actor_type == "vector") + { + this->mVFActor->SetVisibility(vis); + } + if (actor_type == "overlay") + { + this->mOverlayActor->SetVisibility(vis); + } + if (actor_type == "fusion") + { + this->mFusionActor->SetVisibility(vis); + } + if (actor_type == "contour") + this->mSurfaceCutActors[overlay_index]->GetActor()->SetVisibility(vis); + UpdateDisplayExtent(); +} + +void vvSlicer::SetVF(vvImage::Pointer vf) +{ + if (vf->GetVTKImages().size()) + { + mVF = vf; + + if (!mAAFilter) + { + mAAFilter=vtkAssignAttribute::New(); + mVOIFilter = vtkExtractVOI::New(); + mVOIFilter->SetSampleRate(mSubSampling,mSubSampling,mSubSampling); + } + mVOIFilter->SetInput(vf->GetVTKImages()[0]); + mAAFilter->SetInput(mVOIFilter->GetOutput()); + ///This tells VTK to use the scalar (pixel) data of the image to draw the little arrows + mAAFilter->Assign(vtkDataSetAttributes::SCALARS, vtkDataSetAttributes::VECTORS, vtkAssignAttribute::POINT_DATA); + + if (!mArrow) + mArrow = vvGlyphSource::New(); + mArrow->SetGlyphTypeToSpecificArrow(); + mArrow->SetScale(mScale); + mArrow->FilledOff(); + + // Glyph the gradient vector (with arrows) + if (!mGlyphFilter) + mGlyphFilter = vvGlyph2D::New(); + mGlyphFilter->SetInput(mAAFilter->GetOutput()); + mGlyphFilter->SetSource(mArrow->GetOutput()); + mGlyphFilter->ScalingOn(); + mGlyphFilter->SetScaleModeToScaleByVector(); + mGlyphFilter->OrientOn(); + mGlyphFilter->SetVectorModeToUseVector(); + mGlyphFilter->SetColorModeToColorByVector(); + + if (!mVFMapper) + mVFMapper = vtkPolyDataMapper::New(); + //mVFMapper->SetInputConnection(mGlyphFilter->GetOutputPort()); + mVFMapper->SetInput(mGlyphFilter->GetOutput()); + mVFMapper->ImmediateModeRenderingOn(); + + if (!mVFActor) + mVFActor = vtkActor::New(); + mVFActor->SetMapper(mVFMapper); + mVFActor->SetPickable(0); + this->UpdateDisplayExtent(); + this->GetRenderer()->AddActor(mVFActor); + + //Synchronize slice + SetTSlice(mCurrentTSlice); + } +} + +void vvSlicer::SetLandmarks(vvLandmarks* landmarks) +{ + mLandmarks = landmarks; + if (landmarks) + { + + if (!mCross) + mCross = vtkCursor3D::New(); + mCross->SetFocalPoint(0.0,0.0,0.0); + mCross->SetModelBounds(-10,10,-10,10,-10,10); + mCross->AllOff(); + mCross->AxesOn(); + + if (!mLandGlyph) + mLandGlyph = vtkGlyph3D::New(); + mLandGlyph->SetSource(mCross->GetOutput()); + mLandGlyph->SetInput(landmarks->GetOutput()); + //mLandGlyph->SetIndexModeToScalar(); + mLandGlyph->SetRange(0,1); + mLandGlyph->ScalingOff(); + + mLandGlyph->SetColorModeToColorByScalar(); + + if (!mClipBox) + mClipBox = vtkBox::New(); + if (!mLandClipper) + mLandClipper = vtkClipPolyData::New(); + mLandClipper->InsideOutOn(); + mLandClipper->SetInput(mLandGlyph->GetOutput()); + mLandClipper->SetClipFunction(mClipBox); + + if (!mLandMapper) + mLandMapper = vtkPolyDataMapper::New(); + mLandMapper->SetInputConnection(mLandClipper->GetOutputPort()); + //mLandMapper->ScalarVisibilityOff(); + + if (!mLandActor) + mLandActor = vtkActor::New(); + mLandActor->SetMapper(mLandMapper); + mLandActor->GetProperty()->SetColor(255,10,212); + mLandActor->SetPickable(0); + mLandActor->SetVisibility(true); + this->UpdateDisplayExtent(); + this->GetRenderer()->AddActor(mLandActor); + } +} + +void vvSlicer::RemoveActor(const std::string& actor_type, int overlay_index) +{ + if (actor_type == "vector") + { + mGlyphFilter=NULL; + mVF = NULL; + mArrow = NULL; + mAAFilter=NULL; + mVOIFilter = NULL; + mVFMapper = NULL; + mVFActor = NULL; + } + if (actor_type == "overlay") + { + Renderer->RemoveActor(mOverlayActor); + mOverlay = NULL; + mOverlayActor = NULL; + mOverlayMapper = NULL; + } + if (actor_type == "fusion") + { + Renderer->RemoveActor(mFusionActor); + mFusion = NULL; + mFusionActor = NULL; + mFusionMapper = NULL; + } + if (actor_type == "contour") + { + Renderer->RemoveActor(this->mSurfaceCutActors[overlay_index]->GetActor()); + mSurfaceCutActors.erase(mSurfaceCutActors.begin()+overlay_index); + } +} + +void vvSlicer::SetVFSubSampling(int sub) +{ + if (mVOIFilter) + { + mVOIFilter->SetSampleRate(mSubSampling,mSubSampling,mSubSampling); + mSubSampling = sub; + } + UpdateDisplayExtent(); + Render(); +} + +void vvSlicer::SetVFScale(int scale) +{ + mScale = scale; + if (mArrow) + mArrow->SetScale(mScale); + UpdateDisplayExtent(); + Render(); +} + +void vvSlicer::SetVFLog(int log) +{ + mVFLog = log; + if (mGlyphFilter) + { + mGlyphFilter->SetUseLog(mVFLog); + mGlyphFilter->Modified(); + } + UpdateDisplayExtent(); + Render(); +} + +void vvSlicer::SetTSlice(int t) +{ + if (t < 0) + t = 0; + else if ((unsigned int)t >= mImage->GetVTKImages().size()) + t = mImage->GetVTKImages().size() -1; + mCurrentTSlice = t; + this->SetInput(mImage->GetVTKImages()[t]); + if (mVF && mVFActor->GetVisibility()) + { + if (mVF->GetVTKImages().size() == 1) + { + mVOIFilter->SetInput(mVF->GetVTKImages()[0]); + } + else if (mVF->GetVTKImages().size() <= (unsigned int)mCurrentTSlice) + { + Renderer->RemoveActor(mVFActor); + } + else + { + if (!Renderer->HasViewProp(mVFActor)) + { + Renderer->AddActor(mVFActor); + } + mVOIFilter->SetInput(mVF->GetVTKImages()[mCurrentTSlice]); + } + } + if (mOverlay && mOverlayActor->GetVisibility()) + { + if (mOverlay->GetVTKImages().size() == 1) + { + mOverlayMapper->SetInput(mOverlay->GetVTKImages()[0]); + } + else if (mOverlay->GetVTKImages().size() <= (unsigned int)mCurrentTSlice) + { + Renderer->RemoveActor(mOverlayActor); + } + else + { + if (!Renderer->HasViewProp(mOverlayActor)) + { + Renderer->AddActor(mOverlayActor); + } + mOverlayMapper->SetInput(mOverlay->GetVTKImages()[mCurrentTSlice]); + } + } + if (mFusion && mFusionActor->GetVisibility()) + { + if (mFusion->GetVTKImages().size() == 1) + { + mFusionMapper->SetInput(mFusion->GetVTKImages()[0]); + } + else if (mFusion->GetVTKImages().size() <= (unsigned int)mCurrentTSlice) + { + Renderer->RemoveActor(mFusionActor); + } + else + { + if (!Renderer->HasViewProp(mFusionActor)) + { + Renderer->AddActor(mFusionActor); + } + mFusionMapper->SetInput(mFusion->GetVTKImages()[mCurrentTSlice]); + } + } + if (mSurfaceCutActors.size() > 0) + for (std::vector::iterator i=mSurfaceCutActors.begin(); + i!=mSurfaceCutActors.end();i++) + (*i)->SetTimeSlice(mCurrentTSlice); + UpdateDisplayExtent(); +} + +int vvSlicer::GetTSlice() +{ + return mCurrentTSlice; +} + +void vvSlicer::SetSliceOrientation(int orientation) +{ + //if 2D image, force to watch in Axial View + int extent[6]; + this->GetInput()->GetWholeExtent(extent); + if (extent[5]-extent[4] <= 2) + orientation=2; + + if (orientation < vtkImageViewer2::SLICE_ORIENTATION_YZ || + orientation > vtkImageViewer2::SLICE_ORIENTATION_XY) + { + vtkErrorMacro("Error - invalid slice orientation " << orientation); + return; + } + + this->SliceOrientation = orientation; + + // Update the viewer + int *range = this->GetSliceRange(); + if (range) + this->Slice = static_cast((range[0] + range[1]) * 0.5); + + this->UpdateOrientation(); + this->UpdateDisplayExtent(); + + if (this->Renderer && this->GetInput()) + { + double scale = this->Renderer->GetActiveCamera()->GetParallelScale(); + this->Renderer->ResetCamera(); + this->Renderer->GetActiveCamera()->SetParallelScale(scale); + } + + SetContourSlice(); +} + +//---------------------------------------------------------------------------- +void vvSlicer::UpdateDisplayExtent() +{ + vtkImageData *input = this->GetInput(); + if (!input || !this->ImageActor) + { + return; + } + input->UpdateInformation(); + int *w_ext = input->GetWholeExtent(); + + switch (this->SliceOrientation) + { + case vtkImageViewer2::SLICE_ORIENTATION_XY: + this->ImageActor->SetDisplayExtent( + w_ext[0], w_ext[1], w_ext[2], w_ext[3], this->Slice, this->Slice); + if (mVF && mVFActor->GetVisibility()) + { + int vfExtent[6]; + ComputeVFDisplayedExtent(w_ext[0], w_ext[1], w_ext[2], w_ext[3], this->Slice, this->Slice,vfExtent); + mVOIFilter->SetVOI(vfExtent); + mGlyphFilter->SetOrientation(1,1,0); + mVFMapper->Update(); + // put the vector field between the image and the camera + if (Renderer->GetActiveCamera()->GetPosition()[2] > this->Slice) + mVFActor->SetPosition(0,0,ImageActor->GetBounds()[5]+2); + else + mVFActor->SetPosition(0,0,ImageActor->GetBounds()[4]-2); + } + if (mOverlay && mOverlayActor->GetVisibility()) + { + int overExtent[6]; + ComputeOverlayDisplayedExtent(w_ext[0], w_ext[1], w_ext[2], w_ext[3], this->Slice, this->Slice,overExtent); + mOverlayActor->SetDisplayExtent(overExtent); + if (Renderer->GetActiveCamera()->GetPosition()[2] > this->Slice) + mOverlayActor->SetPosition(0,0,1); + else + mOverlayActor->SetPosition(0,0,-1); + } + if (mFusion && mFusionActor->GetVisibility()) + { + int fusExtent[6]; + ComputeFusionDisplayedExtent(w_ext[0], w_ext[1], w_ext[2], w_ext[3], this->Slice, this->Slice,fusExtent); + mFusionActor->SetDisplayExtent(fusExtent); + if (Renderer->GetActiveCamera()->GetPosition()[2] > this->Slice) + mFusionActor->SetPosition(0,0,1.5); + else + mFusionActor->SetPosition(0,0,-1.5); + } + if (mLandActor) + { + if (mClipBox) + { + double bounds [6]; + bounds[0] = ImageActor->GetBounds()[0]; + bounds[1] = ImageActor->GetBounds()[1]; + bounds[2] = ImageActor->GetBounds()[2]; + bounds[3] = ImageActor->GetBounds()[3]; + bounds[4] = ImageActor->GetBounds()[4]-(0.9/this->GetInput()->GetSpacing()[2]); + bounds[5] = ImageActor->GetBounds()[5]+(0.9/this->GetInput()->GetSpacing()[2]); + mClipBox->SetBounds(bounds); + UpdateLandmarks(); + } + if (Renderer->GetActiveCamera()->GetPosition()[2] > this->Slice) + mLandActor->SetPosition(0,0,1.5); + else + mLandActor->SetPosition(0,0,-1.5); + } + break; + + case vtkImageViewer2::SLICE_ORIENTATION_XZ: + this->ImageActor->SetDisplayExtent( + w_ext[0], w_ext[1], this->Slice, this->Slice, w_ext[4], w_ext[5]); + if (mVF && mVFActor->GetVisibility()) + { + int vfExtent[6]; + ComputeVFDisplayedExtent(w_ext[0], w_ext[1], this->Slice, this->Slice, w_ext[4], w_ext[5],vfExtent); + mVOIFilter->SetVOI(vfExtent); + mGlyphFilter->SetOrientation(1,0,1); + mVFMapper->Update(); + // put the vector field between the image aSpacingnd the camera + if (Renderer->GetActiveCamera()->GetPosition()[1] > this->Slice) + mVFActor->SetPosition(0,ImageActor->GetBounds()[3]+2,0); + else + mVFActor->SetPosition(0,ImageActor->GetBounds()[2]-2,0); + } + if (mOverlay && mOverlayActor->GetVisibility()) + { + int overExtent[6]; + ComputeOverlayDisplayedExtent(w_ext[0], w_ext[1], this->Slice, this->Slice, w_ext[4], w_ext[5],overExtent); + mOverlayActor->SetDisplayExtent(overExtent); + if (Renderer->GetActiveCamera()->GetPosition()[1] > this->Slice) + mOverlayActor->SetPosition(0,1,0); + else + mOverlayActor->SetPosition(0,-1,0); + } + if (mFusion && mFusionActor->GetVisibility()) + { + int fusExtent[6]; + ComputeFusionDisplayedExtent(w_ext[0], w_ext[1], this->Slice, this->Slice, w_ext[4], w_ext[5],fusExtent); + mFusionActor->SetDisplayExtent(fusExtent); + if (Renderer->GetActiveCamera()->GetPosition()[1] > this->Slice) + mFusionActor->SetPosition(0,1.5,0); + else + mFusionActor->SetPosition(0,-1.5,0); + } + if (mLandActor) + { + if (mClipBox) + { + double bounds [6]; + bounds[0] = ImageActor->GetBounds()[0]; + bounds[1] = ImageActor->GetBounds()[1]; + bounds[2] = ImageActor->GetBounds()[2]-(0.5/this->GetInput()->GetSpacing()[1]); + bounds[3] = ImageActor->GetBounds()[3]+(0.5/this->GetInput()->GetSpacing()[1]); + bounds[4] = ImageActor->GetBounds()[4]; + bounds[5] = ImageActor->GetBounds()[5]; + mClipBox->SetBounds(bounds); + UpdateLandmarks(); + } + if (Renderer->GetActiveCamera()->GetPosition()[1] > this->Slice) + mLandActor->SetPosition(0,1.5,0); + else + mLandActor->SetPosition(0,-1.5,0); + } + break; + + case vtkImageViewer2::SLICE_ORIENTATION_YZ: + this->ImageActor->SetDisplayExtent( + this->Slice, this->Slice, w_ext[2], w_ext[3], w_ext[4], w_ext[5]); + if (mVF && mVFActor->GetVisibility()) + { + int vfExtent[6]; + ComputeVFDisplayedExtent(this->Slice, this->Slice, w_ext[2], w_ext[3], w_ext[4], w_ext[5],vfExtent); + mVOIFilter->SetVOI(vfExtent); + mGlyphFilter->SetOrientation(0,1,1); + mVFMapper->Update(); + // put the vector field between the image and the camera + if (Renderer->GetActiveCamera()->GetPosition()[0] > this->Slice) + mVFActor->SetPosition(ImageActor->GetBounds()[1]+2,0,0); + else + mVFActor->SetPosition(ImageActor->GetBounds()[0]-2,0,0); + } + if (mOverlay && mOverlayActor->GetVisibility()) + { + int overExtent[6]; + ComputeOverlayDisplayedExtent(this->Slice, this->Slice, w_ext[2], w_ext[3], w_ext[4], w_ext[5],overExtent); + mOverlayActor->SetDisplayExtent(overExtent); + if (Renderer->GetActiveCamera()->GetPosition()[0] > this->Slice) + mOverlayActor->SetPosition(1,0,0); + else + mOverlayActor->SetPosition(-1,0,0); + } + if (mFusion && mFusionActor->GetVisibility()) + { + int fusExtent[6]; + ComputeFusionDisplayedExtent(this->Slice, this->Slice, w_ext[2], w_ext[3], w_ext[4], w_ext[5],fusExtent); + mFusionActor->SetDisplayExtent(fusExtent); + if (Renderer->GetActiveCamera()->GetPosition()[0] > this->Slice) + mFusionActor->SetPosition(1.5,0,0); + else + mFusionActor->SetPosition(-1.5,0,0); + } + if (mLandActor) + { + if (mClipBox) + { + double bounds [6]; + bounds[0] = ImageActor->GetBounds()[0]-(0.5/this->GetInput()->GetSpacing()[0]); + bounds[1] = ImageActor->GetBounds()[1]+(0.5/this->GetInput()->GetSpacing()[0]); + bounds[2] = ImageActor->GetBounds()[2]; + bounds[3] = ImageActor->GetBounds()[3]; + bounds[4] = ImageActor->GetBounds()[4]; + bounds[5] = ImageActor->GetBounds()[5]; + mClipBox->SetBounds(bounds); + UpdateLandmarks(); + } + if (Renderer->GetActiveCamera()->GetPosition()[0] > this->Slice) + mLandActor->SetPosition(1.5,0,0); + else + mLandActor->SetPosition(-1.5,0,0); + } + break; + } + + // Figure out the correct clipping range + + if (this->Renderer) + { + if (this->InteractorStyle && + this->InteractorStyle->GetAutoAdjustCameraClippingRange()) + { + this->Renderer->ResetCameraClippingRange(); + } + else + { + vtkCamera *cam = this->Renderer->GetActiveCamera(); + if (cam) + { + double bounds[6]; + this->ImageActor->GetBounds(bounds); + double spos = (double)bounds[this->SliceOrientation * 2]; + double cpos = (double)cam->GetPosition()[this->SliceOrientation]; + double range = fabs(spos - cpos); + double *spacing = input->GetSpacing(); + double avg_spacing = + ((double)spacing[0] + (double)spacing[1] + (double)spacing[2]) / 3.0; + cam->SetClippingRange( + range - avg_spacing * 3.0, range + avg_spacing * 3.0); + } + } + } +} + +void vvSlicer::ComputeVFDisplayedExtent(int x1,int x2,int y1,int y2,int z1,int z2,int vfExtent[6]) +{ + vtkImageData* image=this->GetInput(); + vfExtent[0] = (( image->GetOrigin()[0] + x1*image->GetSpacing()[0] ) - mVF->GetOrigin()[0]) / + mVF->GetSpacing()[0]; + vfExtent[1] = (( image->GetOrigin()[0] + x2*image->GetSpacing()[0] ) - mVF->GetOrigin()[0]) / + mVF->GetSpacing()[0]; + vfExtent[2] = (( image->GetOrigin()[1] + y1*image->GetSpacing()[1] ) - mVF->GetOrigin()[1]) / + mVF->GetSpacing()[1]; + vfExtent[3] = (( image->GetOrigin()[1] + y2*image->GetSpacing()[1] ) - mVF->GetOrigin()[1]) / + mVF->GetSpacing()[1]; + vfExtent[4] = (( image->GetOrigin()[2] + z1*image->GetSpacing()[2] ) - mVF->GetOrigin()[2]) / + mVF->GetSpacing()[2]; + vfExtent[5] = (( image->GetOrigin()[2] + z2*image->GetSpacing()[2] ) - mVF->GetOrigin()[2]) / + mVF->GetSpacing()[2]; + + ClipDisplayedExtent(vfExtent,mVOIFilter->GetInput()->GetWholeExtent()); +} + +void vvSlicer::ComputeOverlayDisplayedExtent(int x1,int x2,int y1,int y2,int z1,int z2,int overExtent[6]) +{ + vtkImageData* image=this->GetInput(); + overExtent[0] = (( image->GetOrigin()[0] + x1*image->GetSpacing()[0] ) - mOverlay->GetOrigin()[0]) / + mOverlay->GetSpacing()[0]; + overExtent[1] = (( image->GetOrigin()[0] + x2*image->GetSpacing()[0] ) - mOverlay->GetOrigin()[0]) / + mOverlay->GetSpacing()[0]; + overExtent[2] = (( image->GetOrigin()[1] + y1*image->GetSpacing()[1] ) - mOverlay->GetOrigin()[1]) / + mOverlay->GetSpacing()[1]; + overExtent[3] = (( image->GetOrigin()[1] + y2*image->GetSpacing()[1] ) - mOverlay->GetOrigin()[1]) / + mOverlay->GetSpacing()[1]; + overExtent[4] = (( image->GetOrigin()[2] + z1*image->GetSpacing()[2] ) - mOverlay->GetOrigin()[2]) / + mOverlay->GetSpacing()[2]; + overExtent[5] = (( image->GetOrigin()[2] + z2*image->GetSpacing()[2] ) - mOverlay->GetOrigin()[2]) / + mOverlay->GetSpacing()[2]; + ClipDisplayedExtent(overExtent, mOverlayMapper->GetInput()->GetWholeExtent()); +} + +void vvSlicer::ComputeFusionDisplayedExtent(int x1,int x2,int y1,int y2,int z1,int z2,int fusExtent[6]) +{ + vtkImageData* image=this->GetInput(); + fusExtent[0] = (( image->GetOrigin()[0] + x1*image->GetSpacing()[0] ) - mFusion->GetOrigin()[0]) / + mFusion->GetSpacing()[0]; + fusExtent[1] = (( image->GetOrigin()[0] + x2*image->GetSpacing()[0] ) - mFusion->GetOrigin()[0]) / + mFusion->GetSpacing()[0]; + fusExtent[2] = (( image->GetOrigin()[1] + y1*image->GetSpacing()[1] ) - mFusion->GetOrigin()[1]) / + mFusion->GetSpacing()[1]; + fusExtent[3] = (( image->GetOrigin()[1] + y2*image->GetSpacing()[1] ) - mFusion->GetOrigin()[1]) / + mFusion->GetSpacing()[1]; + fusExtent[4] = (( image->GetOrigin()[2] + z1*image->GetSpacing()[2] ) - mFusion->GetOrigin()[2]) / + mFusion->GetSpacing()[2]; + fusExtent[5] = (( image->GetOrigin()[2] + z2*image->GetSpacing()[2] ) - mFusion->GetOrigin()[2]) / + mFusion->GetSpacing()[2]; + ClipDisplayedExtent(fusExtent, mFusionMapper->GetInput()->GetWholeExtent()); +} + +void vvSlicer::ClipDisplayedExtent(int extent[6], int refExtent[6]) +{ + bool out = false; + int maxBound = 6; + + //2D overlay on 3D image specific case + if (refExtent[4] == refExtent[5]) + { + maxBound = 4; + extent[4] = refExtent[4]; + extent[5] = refExtent[5]; + } + + for (int i = 0; i < maxBound; i = i+2) + { + //if we are totally outside the image + if ( extent[i] > refExtent[i+1] or extent[i+1] < refExtent[i] ) + { + out = true; + break; + } + //crop to the limit of the image + extent[i] = (extent[i] > refExtent[i]) ? extent[i] : refExtent[i]; + extent[i] = (extent[i] < refExtent[i+1]) ? extent[i] : refExtent[i+1]; + extent[i+1] = (extent[i+1] > refExtent[i]) ? extent[i+1] : refExtent[i]; + extent[i+1] = (extent[i+1] < refExtent[i+1]) ? extent[i+1] : refExtent[i+1]; + } + if (out) + for (int i = 0; i < maxBound; i = i+2) + { + extent[i] = refExtent[i]; + extent[i+1] = refExtent[i]; + } +} + +void vvSlicer::UpdateOrientation() +{ + // Set the camera position + vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : NULL; + if (cam) + { + switch (this->SliceOrientation) + { + case vtkImageViewer2::SLICE_ORIENTATION_XY: + cam->SetFocalPoint(0,0,0); + cam->SetPosition(0,0,-1); // -1 if medical ? + cam->SetViewUp(0,-1,0); + break; + + case vtkImageViewer2::SLICE_ORIENTATION_XZ: + cam->SetFocalPoint(0,0,0); + cam->SetPosition(0,-1,0); // 1 if medical ? + cam->SetViewUp(0,0,1); + break; + + case vtkImageViewer2::SLICE_ORIENTATION_YZ: + cam->SetFocalPoint(0,0,0); + cam->SetPosition(-1,0,0); // -1 if medical ? + cam->SetViewUp(0,0,1); + break; + } + } +} + +void vvSlicer::SetOpacity(double s) +{ + this->GetImageActor()->SetOpacity(s); +} + +void vvSlicer::SetRenderWindow(int orientation, vtkRenderWindow * rw) +{ + this->Superclass::SetRenderWindow(rw); + this->SetupInteractor(rw->GetInteractor()); + ca->SetImageActor(this->GetImageActor()); + ca->SetWindowLevel(this->GetWindowLevel()); + ca->SetText(2, ""); + ca->SetText(3, "\n"); + + double bounds[6]; + double max = 65000; + + bounds[0] = -max; + bounds[1] = max; + bounds[2] = -max; + bounds[3] = max; + bounds[4] = -max; + bounds[5] = max; + + crossCursor->SetModelBounds(bounds); + this->GetRenderer()->AddActor(pdmA); + this->GetRenderer()->AddActor(ca); + this->GetRenderer()->ResetCamera(); + + //this is just a mapping between the labeling of the orientations presented to the user and + //the one used by vtk + SetSliceOrientation(2-(orientation%3)); + ResetCamera(); +} + +void vvSlicer::ResetCamera() +{ + if (this->GetInput()) + { + double* input_bounds=this->GetInput()->GetBounds(); + double bmax=input_bounds[1]-input_bounds[0]; + if (bmax < input_bounds[3]-input_bounds[2]) bmax=input_bounds[3]-input_bounds[2]; + if (bmax < input_bounds[5]-input_bounds[4]) bmax=input_bounds[5]-input_bounds[4]; + this->GetRenderer()->ResetCamera(); + this->GetRenderer()->GetActiveCamera()->SetParallelScale(bmax/2); + } +} + +void vvSlicer::SetDisplayMode(bool i) +{ + this->GetImageActor()->SetVisibility(i); + this->GetAnnotation()->SetVisibility(i); + this->GetRenderer()->SetDraw(i); + if (mLandActor) + mLandActor->SetVisibility(i); + pdmA->SetVisibility(i); + if (i) + UpdateDisplayExtent(); +} + +void vvSlicer::FlipHorizontalView() +{ + vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : NULL; + if (cam) + { + double *position = cam->GetPosition(); + switch (this->SliceOrientation) + { + case vtkImageViewer2::SLICE_ORIENTATION_XY: + cam->SetPosition(position[0],position[1],-position[2]); + break; + + case vtkImageViewer2::SLICE_ORIENTATION_XZ: + cam->SetPosition(position[0],-position[1],position[2]); + break; + + case vtkImageViewer2::SLICE_ORIENTATION_YZ: + cam->SetPosition(-position[0],position[1],position[2]); + break; + } + this->Renderer->ResetCameraClippingRange(); + this->UpdateDisplayExtent(); + } +} + +void vvSlicer::FlipVerticalView() +{ + vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : NULL; + if (cam) + { + FlipHorizontalView(); + double *viewup = cam->GetViewUp(); + cam->SetViewUp(-viewup[0],-viewup[1],-viewup[2]); + this->UpdateDisplayExtent(); + } +} + +void vvSlicer::Render() +{ + if (this->GetWindowLevel()->GetLookupTable() and not this->mOverlay and not + this->mFusion) + { + legend->SetLookupTable(this->GetWindowLevel()->GetLookupTable()); + legend->SetVisibility(1); + } + else legend->SetVisibility(0); + + if (ca->GetVisibility()) + { + std::string worldPos = ""; + std::stringstream world1; + std::stringstream world2; + std::stringstream world3; + world1 << (int)mCurrent[0]; + world2 << (int)mCurrent[1]; + world3 << (int)mCurrent[2]; + double X = (mCurrent[0] - this->GetInput()->GetOrigin()[0])/this->GetInput()->GetSpacing()[0]; + double Y = (mCurrent[1] - this->GetInput()->GetOrigin()[1])/this->GetInput()->GetSpacing()[1]; + double Z = (mCurrent[2] - this->GetInput()->GetOrigin()[2])/this->GetInput()->GetSpacing()[2]; + + if (pdmA->GetVisibility()) + { + double x = mCursor[0]; + double y = mCursor[1]; + double z = mCursor[2]; + double xCursor = (x - this->GetInput()->GetOrigin()[0])/this->GetInput()->GetSpacing()[0]; + double yCursor = (y - this->GetInput()->GetOrigin()[1])/this->GetInput()->GetSpacing()[1]; + double zCursor = (z - this->GetInput()->GetOrigin()[2])/this->GetInput()->GetSpacing()[2]; + + if (xCursor >= this->GetImageActor()->GetDisplayExtent()[0] && + xCursor < this->GetImageActor()->GetDisplayExtent()[1]+1 && + yCursor >= this->GetImageActor()->GetDisplayExtent()[2] && + yCursor < this->GetImageActor()->GetDisplayExtent()[3]+1 && + zCursor >= this->GetImageActor()->GetDisplayExtent()[4] && + zCursor < this->GetImageActor()->GetDisplayExtent()[5]+1 ) + { + vtkRenderer * renderer = this->Renderer; + + renderer->WorldToView(x,y,z); + renderer->ViewToNormalizedViewport(x,y,z); + renderer->NormalizedViewportToViewport(x,y); + renderer->ViewportToNormalizedDisplay(x,y); + renderer->NormalizedDisplayToDisplay(x,y); + crossCursor->SetFocalPoint(x,y,z); + } + else + crossCursor->SetFocalPoint(-1,-1,z); + } + + if (X >= this->GetInput()->GetWholeExtent()[0] && + X <= this->GetInput()->GetWholeExtent()[1] && + Y >= this->GetInput()->GetWholeExtent()[2] && + Y <= this->GetInput()->GetWholeExtent()[3] && + Z >= this->GetInput()->GetWholeExtent()[4] && + Z <= this->GetInput()->GetWholeExtent()[5]) + { + std::stringstream pixel1; + std::stringstream pixel2; + std::stringstream pixel3; + std::stringstream temps; + pixel1 << (int)X; + pixel2 << (int)Y; + pixel3 << (int)Z; + temps << mCurrentTSlice; + double value = this->GetInput()->GetScalarComponentAsDouble( + (int)X, + (int)Y, + (int)Z,0); + + std::stringstream val; + val << value; + worldPos += "data value : " + val.str(); + worldPos += "\n mm : " + world1.str() + " " + world2.str() + " " + world3.str() + " " + temps.str(); + worldPos += "\n pixel : " + pixel1.str() + " " + pixel2.str() + " " + pixel3.str() + " " + temps.str(); + } + ca->SetText(1,worldPos.c_str()); + } + if (mOverlay && mOverlayActor->GetVisibility()) + { + mOverlayMapper->SetWindow(this->GetColorWindow()); + mOverlayMapper->SetLevel(this->GetColorLevel()); + mOverlayMapper->Update(); + } + if (mLandMapper) + UpdateLandmarks(); + //this->Superclass::Render(); + this->GetRenderWindow()->Render(); +} + +void vvSlicer::UpdateCursorPosition() +{ + if (this->GetImageActor()->GetVisibility()) + { + pdmA->SetVisibility(true); + mCursor[0] = mCurrent[0]; + mCursor[1] = mCurrent[1]; + mCursor[2] = mCurrent[2]; + mCursor[3] = mCurrentTSlice; + } +} + +void vvSlicer::UpdateLandmarks() +{ + vtkPolyData *pd = static_cast(mLandClipper->GetInput()); + if (pd->GetPoints()) + { + mLandGlyph->SetRange(0,1); + mLandGlyph->Modified(); + mLandGlyph->Update(); + + mClipBox->Modified(); + mLandClipper->Update(); + mLandMapper->Update(); + } + +} + +//---------------------------------------------------------------------------- +void vvSlicer::SetSlice(int slice) +{ + int *range = this->GetSliceRange(); + if (range) + { + if (slice < range[0]) + { + slice = range[0]; + } + else if (slice > range[1]) + { + slice = range[1]; + } + } + + if (this->Slice == slice) + { + return; + } + + this->Slice = slice; + SetContourSlice(); + this->Modified(); + this->UpdateDisplayExtent(); + this->Render(); +} + +void vvSlicer::SetContourSlice() +{ + if (mSurfaceCutActors.size() > 0) + for (std::vector::iterator i=mSurfaceCutActors.begin(); + i!=mSurfaceCutActors.end();i++) + (*i)->SetCutSlice((this->Slice)*this->GetImage()->GetSpacing()[this->SliceOrientation]+ + this->GetImage()->GetOrigin()[this->SliceOrientation]); +} + +void vvSlicer::ForceUpdateDisplayExtent() +{ + this->UpdateDisplayExtent(); +} + +int* vvSlicer::GetDisplayExtent() +{ + return this->GetImageActor()->GetDisplayExtent(); +} + +void vvSlicer::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} diff --git a/vv/vvSlicer.h b/vv/vvSlicer.h new file mode 100644 index 0000000..184df43 --- /dev/null +++ b/vv/vvSlicer.h @@ -0,0 +1,221 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvSlicer.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef __vvSlicer_h +#define __vvSlicer_h + +#include +#include + +#include "vvLandmarks.h" +#include "vvImage.h" +#include "vtkImageViewer2.h" +#include "vvMesh.h" +#include +#include + +class vtkActor; +class vtkActor2D; +class vtkCursor2D; +class vtkPolyDataMapper2D; +class vtkProperty2D; +class vtkClipPolyData; +class vtkImageActor; +class vtkBox; +class vtkCornerAnnotation; +class vtkExtractVOI; +class vtkPolyDataMapper2D; +class vtkPolyDataMapper; +class vtkGlyph3D; +class vvGlyph2D; +class vvGlyphSource; +class vtkCursor3D; +class vtkCutter; +class vtkPlane; +class vtkAssignAttribute; +class vtkScalarBarActor; + + +class vvSlicer: public vtkImageViewer2 +{ +public: + static vvSlicer *New(); + vtkTypeRevisionMacro(vvSlicer,vtkImageViewer2); + void PrintSelf(ostream& os, vtkIndent indent); + + void SetImage(vvImage::Pointer inputImages); + vvImage::Pointer GetImage() { + return mImage; + } + + void SetOverlay(vvImage::Pointer inputOverlay); + vvImage::Pointer GetOverlay() { + return mOverlay; + } + + vtkImageMapToWindowLevelColors* GetOverlayMapper(); + vtkImageActor* GetOverlayActor() ; + vtkImageMapToWindowLevelColors* GetFusionMapper() ; + vtkImageActor* GetFusionActor() ; + vtkActor* GetVFActor() ; + vtkCornerAnnotation* GetAnnotation() ; + + void SetFusion(vvImage::Pointer inputFusion); + vvImage::Pointer GetFusion() { + return mFusion; + } + + /**Set an actor's visibility ("overlay, fusion, vf, contour...") + Overlay index is the index of the overlay by type, eg. if there are + 5 contours and we want to activate the 3rd one, pass 2 **/ + void SetActorVisibility(const std::string& actor_type, int overlay_index,bool vis); + void RemoveActor(const std::string& actor_type, int overlay_index); + + void SetVF(vvImage::Pointer vf); + vvImage *GetVF() { + return mVF; + } + + void SetLandmarks(vvLandmarks* landmarks); + void SetTSlice(int t); + void SetSliceOrientation(int orientation); + int GetTSlice(); + ///Reimplemented from vtkImageViewer2 to add polydata support + void SetSlice(int s); + int GetTMax() { + return mImage->GetVTKImages().size() - 1; + } + + void SetOpacity(double s); + void SetRenderWindow(int orientation, vtkRenderWindow * rw); + void SetDisplayMode(bool i); + void FlipHorizontalView(); + void FlipVerticalView(); + void Render(); + ///Sets the camera to fit the image in the window + void ResetCamera(); + + void SetVFSubSampling(int sub); + int GetVFSubSampling() { + return mSubSampling; + } + void SetVFScale(int scale); + int GetVFScale() { + return mScale; + } + void SetVFLog(int log); + int GetVFLog() { + return mVFLog; + } + + void SetFileName(std::string filename) { + mFileName = filename; + } + std::string GetFileName() { + return mFileName; + } + + double* GetCursorPosition() { + return mCursor; + } + + void SetCurrentPosition(double x, double y, double z, int t); + double* GetCurrentPosition() { + return mCurrent; + } + + void UpdateCursorPosition(); + void SetCursorVisibility(bool s); + bool GetCursorVisibility(); + void SetCursorColor(int r,int g, int b); + + void UpdateLandmarks(); + void ForceUpdateDisplayExtent(); + + int* GetDisplayExtent(); + /**Add a polydata to be displayed as a contour over the image + ** the contour can be propagated to a time sequence using a motion field */ + void AddContour(vvMesh::Pointer contours,bool propagate); + ///Toggle temporal superposition of contours + void ToggleContourSuperposition(); + +protected: + vvSlicer(); + ~vvSlicer(); + + std::string mFileName; + vvImage::Pointer mImage; + vvImage::Pointer mOverlay; + vvImage::Pointer mFusion; + vvImage::Pointer mVF; + + vvLandmarks* mLandmarks; + + vtkSmartPointer mOverlayMapper; + vtkSmartPointer mOverlayActor; + vtkSmartPointer mFusionMapper; + vtkSmartPointer mFusionActor; + vtkSmartPointer ca; + vtkSmartPointer crossCursor; + vtkSmartPointer pdm; + vtkSmartPointer pdmA; + vtkSmartPointer mArrow; + vtkSmartPointer mAAFilter; + vtkSmartPointer mVOIFilter; + vtkSmartPointer mGlyphFilter; + vtkSmartPointer mVFMapper; + vtkSmartPointer mVFActor; + vtkSmartPointer mLandGlyph; + vtkSmartPointer mCross; + vtkSmartPointer mLandClipper; + vtkSmartPointer mLandMapper; + vtkSmartPointer mLandActor; + vtkSmartPointer mClipBox; + vtkSmartPointer mSlicePlane; + vtkSmartPointer legend; + + std::vector mSurfaceCutActors; + + int mCurrentTSlice; + double mCurrent[3]; + double mCursor[4]; + int mSubSampling; + int mScale; + int mVFLog; + +private: + void UpdateOrientation(); + void UpdateDisplayExtent(); + void ComputeVFDisplayedExtent(int x1,int x2,int y1,int y2,int z1,int z2,int extent[6]); + void ComputeOverlayDisplayedExtent(int x1,int x2,int y1,int y2,int z1,int z2,int overExtent[6]); + void ComputeFusionDisplayedExtent(int x1,int x2,int y1,int y2,int z1,int z2,int overExtent[6]); + void ClipDisplayedExtent(int extent[6], int refExtent[6]); + ///Sets the surfaces to be cut on the image slice: update the vtkCutter + void SetContourSlice(); + + +}; +#endif diff --git a/vv/vvSlicerManager.cxx b/vv/vvSlicerManager.cxx new file mode 100644 index 0000000..9b3d61e --- /dev/null +++ b/vv/vvSlicerManager.cxx @@ -0,0 +1,994 @@ +/*========================================================================= + +Program: vv +Module: $RCSfile: vvSlicerManager.cxx,v $ +Language: C++ +Date: $Date: 2010/01/06 13:31:57 $ +Version: $Revision: 1.1 $ +Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#include "vvSlicerManager.h" + +#include "vvSlicer.h" +#include "vvImage.h" +#include "vvSlicerManagerCommand.h" +#include "vvInteractorStyleNavigator.h" +#include "vvLandmarks.h" +#include "vvImageReader.h" +#include "vvImageReader.h" +#include "vvMesh.h" +#include "vvImageMapToWLColors.h" + +#include "vtkImageActor.h" +#include "vtkImageData.h" +#include "vtkRenderWindow.h" +#include "vtkRendererCollection.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkImageMapToWindowLevelColors.h" +#include "vtkWindowLevelLookupTable.h" +#include "vtkColorTransferFunction.h" +#include "vtkImageClip.h" +#include +#include + +#include +//---------------------------------------------------------------------------- + +vvSlicerManager::vvSlicerManager(int numberOfSlicers) +{ + mFileName = ""; + mId = ""; + mVFName = ""; + mOverlayName = ""; + mFusionName = ""; + mVFId = ""; + mLastError = ""; + mType = UNDEFINEDIMAGETYPE; + mColorMap = 0; + mPreset = 0; + mOverlayColor = 130; + + mFusionOpacity = 70; + mFusionColorMap = 3; + mFusionWindow = 1000; + mFusionLevel = 1000; + + mReader = NULL; + mImage = NULL; + mVF=NULL; + mVectorReader = NULL; + mOverlayReader = NULL; + mFusionReader = NULL; + mLandmarks = NULL; + mLinkedId.resize(0); + + for ( int i = 0; i < numberOfSlicers; i++) + { + vvSlicer *slicer = vvSlicer::New(); + mSlicers.push_back(slicer); + } +} + +vvSlicerManager::~vvSlicerManager() +{ + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + if (mSlicers[i] != NULL) + mSlicers[i]->Delete(); + } + if (mReader) + { + delete mReader; + } + if (mVectorReader) + { + delete mVectorReader; + } + if (mOverlayReader) + { + delete mOverlayReader; + } + if (mFusionReader) + { + delete mFusionReader; + } + if (mLandmarks) + delete mLandmarks; +} + +void vvSlicerManager::AddContour(vvMesh::Pointer contour,bool propagate) +{ + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + mSlicers[i]->AddContour(contour,propagate); + } +} + +void vvSlicerManager::ToggleContourSuperposition() +{ + for ( unsigned int i = 0; i < mSlicers.size(); i++) + mSlicers[i]->ToggleContourSuperposition(); +} + +bool vvSlicerManager::SetImage(std::string filename,LoadedImageType type) +{ + mFileName = filename; + mType = type; + if (mReader == NULL) + mReader = new vvImageReader; + std::vector filenames; + filenames.push_back(filename); + mReader->SetInputFilenames(filenames); + mReader->Update(type); + if (mReader->GetLastError().size() == 0) + { + mImage=mReader->GetOutput(); + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + mSlicers[i]->SetFileName(vtksys::SystemTools::GetFilenameWithoutLastExtension(filename)); + mSlicers[i]->SetImage(mReader->GetOutput()); + } + } + else + { + mLastError = mReader->GetLastError(); + return false; + } + return true; +} + +void vvSlicerManager::SetImage(vvImage::Pointer image) +{ + mImage=image; + for (unsigned int i = 0; i < mSlicers.size();i++) + { + mSlicers[i]->SetImage(image); + } +} + +bool vvSlicerManager::SetImages(std::vector filenames,LoadedImageType type) +{ + mType = type; + std::string fileWithoutExtension = vtksys::SystemTools::GetFilenameWithoutExtension(filenames[0]); + if (type == DICOM) + fileWithoutExtension += "_dicom"; + else if (type == MERGED) + fileWithoutExtension += "_merged"; + else if (type == MERGEDWITHTIME) + fileWithoutExtension += "_merged_wt"; + + mFileName = fileWithoutExtension + vtksys::SystemTools::GetFilenameExtension(filenames[0]); + if (mReader == NULL) + mReader = new vvImageReader; + mReader->SetInputFilenames(filenames); + mReader->Update(type); + + + if (mReader->GetLastError().size() == 0) + { + mImage=mReader->GetOutput(); + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + mSlicers[i]->SetFileName(fileWithoutExtension); + mSlicers[i]->SetImage(mReader->GetOutput()); + } + } + else + { + mLastError = mReader->GetLastError(); + return false; + } + return true; +} + +bool vvSlicerManager::SetOverlay(std::string filename,int dim, std::string component) +{ + mOverlayName = filename; + mOverlayComponent = component; + if (dim > mImage->GetNumberOfDimensions()) + { + mLastError = " Overlay dimension cannot be greater then reference image!"; + return false; + } + if (mOverlayReader == NULL) + mOverlayReader = new vvImageReader; + std::vector filenames; + filenames.push_back(filename); + mOverlayReader->SetInputFilenames(filenames); + mOverlayReader->Update(mImage->GetNumberOfDimensions(),component.c_str(),mType); + if (mOverlayReader->GetLastError().size() == 0) + { + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + mSlicers[i]->SetOverlay(mOverlayReader->GetOutput()); + } + } + else + { + mLastError = mOverlayReader->GetLastError(); + return false; + } + return true; +} + +bool vvSlicerManager::SetFusion(std::string filename,int dim, std::string component) +{ + mFusionName = filename; + mFusionComponent = component; + if (dim > mImage->GetNumberOfDimensions()) + { + mLastError = " Overlay dimension cannot be greater then reference image!"; + return false; + } + if (mFusionReader == NULL) + mFusionReader = new vvImageReader; + std::vector filenames; + filenames.push_back(filename); + mFusionReader->SetInputFilenames(filenames); + mFusionReader->Update(mImage->GetNumberOfDimensions(),component.c_str(),mType); + if (mFusionReader->GetLastError().size() == 0) + { + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + mSlicers[i]->SetFusion(mFusionReader->GetOutput()); + } + } + else + { + mLastError = mFusionReader->GetLastError(); + return false; + } + double *fusRange = mFusionReader->GetOutput()->GetVTKImages()[0]->GetScalarRange(); + mFusionLevel = (fusRange[0]+fusRange[1])/2; + mFusionWindow = fusRange[1]-fusRange[0]; + return true; +} + +bool vvSlicerManager::SetVF(std::string filename) +{ + if (mVectorReader == NULL) + mVectorReader = new vvImageReader; + mVectorReader->SetInputFilename(filename); + mVectorReader->Update(VECTORFIELD); + if (mVectorReader->GetLastError().size() != 0) + { + mLastError = mVectorReader->GetLastError(); + return false; + } + else + return SetVF(mVectorReader->GetOutput(),filename); +} + +bool vvSlicerManager::SetVF(vvImage::Pointer vf,std::string filename) +{ + if (vf->GetNumberOfDimensions() > mImage->GetNumberOfDimensions()) + { + mLastError = " Vector field dimension cannot be greater then reference image!"; + return false; + } + mVF=vf; + mVFName = filename; + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + mSlicers[i]->SetVF(vf); + } + return true; +} + +void vvSlicerManager::SetExtractedImage(std::string filename,vvImage::Pointer image, int slice) +{ + mFileName = filename; + mImage = vvImage::New(); + if (image->GetNumberOfDimensions() == 4) + { + mImage->AddImage(image->GetVTKImages()[slice]); + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + mSlicers[i]->SetFileName(vtksys::SystemTools::GetFilenameWithoutLastExtension(filename)); + mSlicers[i]->SetImage(mImage); + } + } + else + { + vtkImageClip* clipper = vtkImageClip::New(); + int extent[6]; + image->GetVTKImages()[0]->GetWholeExtent(extent); + clipper->SetInput(image->GetVTKImages()[0]); + clipper->SetOutputWholeExtent(extent[0],extent[1],extent[2],extent[3],slice,slice); + clipper->Update(); + mImage->AddImage(clipper->GetOutput()); + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + mSlicers[i]->SetFileName(vtksys::SystemTools::GetFilenameWithoutLastExtension(filename)); + mSlicers[i]->SetImage(mImage); + } + clipper->Delete(); + } +} + +vvSlicer* vvSlicerManager::GetSlicer(int i) +{ + return mSlicers[i]; +} + +void vvSlicerManager::UpdateSlicer(int num, bool state) +{ + if (mSlicers[num]->GetImage()) + mSlicers[num]->SetDisplayMode(state); +} + +void vvSlicerManager::SetSlicerWindow(int i, vtkRenderWindow* RW) +{ + mSlicers[i]->SetRenderWindow(i,RW); +} + +void vvSlicerManager::SetInteractorStyleNavigator(int i, vtkInteractorStyle* style) +{ + vvSlicerManagerCallback *smc = vvSlicerManagerCallback::New(); + smc->SM = this; + mSlicers[i]->GetRenderWindow()->GetInteractor()->SetInteractorStyle(style); + + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::KeyPressEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::WindowLevelEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::EndWindowLevelEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::StartWindowLevelEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::PickEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::StartPickEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::LeaveEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::UserEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::MouseWheelForwardEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::MouseWheelBackwardEvent, smc); + smc->Delete(); +} + +void vvSlicerManager::SetTSlice(int slice) +{ + if (slice < 0) + slice = 0; + else if (slice > mSlicers[0]->GetTMax()) + slice = mSlicers[0]->GetTMax(); + if (mLandmarks) + mLandmarks->SetTime(slice); + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + mSlicers[i]->SetTSlice(slice); + if (mSlicers[i]->GetImageActor()->GetVisibility()) + UpdateTSlice(i); + } +} + +void vvSlicerManager::SetNextTSlice(int originating_slicer) +{ + int t = mSlicers[0]->GetTSlice(); + t++; + if (t > mSlicers[0]->GetTMax()) + t = 0; + emit UpdateTSlice(originating_slicer,t); +} + +void vvSlicerManager::SetPreviousTSlice(int originating_slicer) +{ + int t = mSlicers[0]->GetTSlice(); + t--; + if (t < 0) + t = mSlicers[0]->GetTMax(); + emit UpdateTSlice(originating_slicer,t); +} + +void vvSlicerManager::ToggleInterpolation() +{ + bool interpolate=not (mSlicers[0]->GetImageActor()->GetInterpolate()); + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + mSlicers[i]->GetImageActor()->SetInterpolate(interpolate); + } +} + + +void vvSlicerManager::SetTSliceInSlicer(int tslice, int slicer) +{ + if (tslice < 0) + tslice = 0; + else if (tslice > mSlicers[slicer]->GetTMax()) + tslice = mSlicers[slicer]->GetTMax(); + if (mLandmarks) + mLandmarks->SetTime(tslice); + mSlicers[slicer]->SetTSlice(tslice); + if (mSlicers[slicer]->GetImageActor()->GetVisibility()) + UpdateTSlice(slicer); +} + +void vvSlicerManager::SetColorWindow(double s) +{ + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + mSlicers[i]->SetColorWindow(s); + } +} + +void vvSlicerManager::SetColorLevel(double s) +{ + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + mSlicers[i]->SetColorLevel(s); + } +} + +void vvSlicerManager::SetCursorVisibility(int s) +{ + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + mSlicers[i]->SetCursorVisibility(s); + } +} + +void vvSlicerManager::SetOpacity(int i, double factor) +{ + mSlicers[i]->SetOpacity(1/factor); +} + +void vvSlicerManager::UpdateViews(int current,int slicer) +{ + double x = (mSlicers[slicer]->GetCurrentPosition()[0] - mSlicers[slicer]->GetInput()->GetOrigin()[0]) + /mSlicers[slicer]->GetInput()->GetSpacing()[0]; + double y = (mSlicers[slicer]->GetCurrentPosition()[1] - mSlicers[slicer]->GetInput()->GetOrigin()[1]) + /mSlicers[slicer]->GetInput()->GetSpacing()[1]; + double z = (mSlicers[slicer]->GetCurrentPosition()[2] - mSlicers[slicer]->GetInput()->GetOrigin()[2]) + /mSlicers[slicer]->GetInput()->GetSpacing()[2]; + + if (x >= mSlicers[slicer]->GetInput()->GetWholeExtent()[0] && + x <= mSlicers[slicer]->GetInput()->GetWholeExtent()[1] && + y >= mSlicers[slicer]->GetInput()->GetWholeExtent()[2] && + y <= mSlicers[slicer]->GetInput()->GetWholeExtent()[3] && + z >= mSlicers[slicer]->GetInput()->GetWholeExtent()[4] && + z <= mSlicers[slicer]->GetInput()->GetWholeExtent()[5]) + { + mSlicers[slicer]->UpdateCursorPosition(); + mSlicers[slicer]->SetCursorColor(10,212,255); + + switch (mSlicers[slicer]->GetSliceOrientation()) + { + case vtkImageViewer2::SLICE_ORIENTATION_XY: + if (mSlicers[slicer]->GetSlice() == (int)floor(z)) + mSlicers[slicer]->Render(); + else + mSlicers[slicer]->SetSlice((int)floor(z)); + break; + + case vtkImageViewer2::SLICE_ORIENTATION_XZ: + if (mSlicers[slicer]->GetSlice() == (int)floor(y)) + mSlicers[slicer]->Render(); + else + mSlicers[slicer]->SetSlice((int)floor(y)); + break; + + case vtkImageViewer2::SLICE_ORIENTATION_YZ: + if (mSlicers[slicer]->GetSlice() == (int)floor(x)) + mSlicers[slicer]->Render(); + else + mSlicers[slicer]->SetSlice((int)floor(x)); + break; + } + + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + if (i != (unsigned int)slicer && mSlicers[i]->GetImageActor()->GetVisibility() + && mSlicers[i]->GetRenderWindow()->GetSize()[0] > 2 + && mSlicers[i]->GetRenderWindow()->GetSize()[1] > 2) + { + mSlicers[i]->SetCurrentPosition(mSlicers[slicer]->GetCurrentPosition()[0], + mSlicers[slicer]->GetCurrentPosition()[1], + mSlicers[slicer]->GetCurrentPosition()[2], + mSlicers[slicer]->GetTSlice()); + mSlicers[i]->UpdateCursorPosition(); + if (current) //do not display corner annotation if image is the one picked + { + mSlicers[i]->SetCurrentPosition(-VTK_DOUBLE_MAX,-VTK_DOUBLE_MAX, + -VTK_DOUBLE_MAX, mSlicers[slicer]->GetTSlice()); + mSlicers[i]->SetCursorColor(255,10,212); + } + else + { + mSlicers[i]->SetCursorColor(150,10,282); + } + switch (mSlicers[i]->GetSliceOrientation()) + { + case vtkImageViewer2::SLICE_ORIENTATION_XY: + if (mSlicers[i]->GetSlice() == (int)floor(z)) + mSlicers[i]->Render(); + else + mSlicers[i]->SetSlice((int)floor(z)); + break; + + case vtkImageViewer2::SLICE_ORIENTATION_XZ: + if (mSlicers[i]->GetSlice() == (int)floor(y)) + mSlicers[i]->Render(); + else + mSlicers[i]->SetSlice((int)floor(y)); + break; + + case vtkImageViewer2::SLICE_ORIENTATION_YZ: + if (mSlicers[i]->GetSlice() == (int)floor(x)) + mSlicers[i]->Render(); + else + mSlicers[i]->SetSlice((int)floor(x)); + break; + } + UpdateSlice(i); + UpdateTSlice(i); + } + } + } +} + +void vvSlicerManager::UpdateLinked(int slicer) +{ + double x = (mSlicers[slicer]->GetCurrentPosition()[0] - mSlicers[slicer]->GetInput()->GetOrigin()[0]) + /mSlicers[slicer]->GetInput()->GetSpacing()[0]; + double y = (mSlicers[slicer]->GetCurrentPosition()[1] - mSlicers[slicer]->GetInput()->GetOrigin()[1]) + /mSlicers[slicer]->GetInput()->GetSpacing()[1]; + double z = (mSlicers[slicer]->GetCurrentPosition()[2] - mSlicers[slicer]->GetInput()->GetOrigin()[2]) + /mSlicers[slicer]->GetInput()->GetSpacing()[2]; + + if (x >= mSlicers[slicer]->GetInput()->GetWholeExtent()[0] && + x <= mSlicers[slicer]->GetInput()->GetWholeExtent()[1] && + y >= mSlicers[slicer]->GetInput()->GetWholeExtent()[2] && + y <= mSlicers[slicer]->GetInput()->GetWholeExtent()[3] && + z >= mSlicers[slicer]->GetInput()->GetWholeExtent()[4] && + z <= mSlicers[slicer]->GetInput()->GetWholeExtent()[5]) + { + for (std::list::const_iterator i = mLinkedId.begin(); i != mLinkedId.end(); i++) + { + emit UpdateLinkManager(*i, slicer,mSlicers[slicer]->GetCurrentPosition()[0], + mSlicers[slicer]->GetCurrentPosition()[1], + mSlicers[slicer]->GetCurrentPosition()[2],mSlicers[slicer]->GetTSlice()); + } + } +} +double vvSlicerManager::GetColorWindow() +{ + if (mSlicers.size()) + return mSlicers[0]->GetColorWindow(); + return -1; +} + +double vvSlicerManager::GetColorLevel() +{ + if (mSlicers.size()) + return mSlicers[0]->GetColorLevel(); + return -1; +} + +void vvSlicerManager::Render() +{ + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + mSlicers[i]->Render(); + } +} + +void vvSlicerManager::GenerateDefaultLookupTable() +{ + SetPreset(mPreset); + SetColorMap(mColorMap); +} + +void vvSlicerManager::Reload() +{ + mReader->Update(mType); + mImage=mReader->GetOutput(); + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + mSlicers[i]->SetImage(mImage); + } +} + +void vvSlicerManager::ReloadVF() +{ + mVectorReader->Update(VECTORFIELD); //deletes the old images through the VF::Init() function + mVF=mVectorReader->GetOutput(); + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + mSlicers[i]->SetVF(mVF); + mSlicers[i]->Render(); + } +} + +void vvSlicerManager::RemoveActor(const std::string& actor_type, int overlay_index) +{ + for (unsigned int i = 0; i < mSlicers.size();i++) + { + mSlicers[i]->RemoveActor(actor_type,overlay_index); + } + if (actor_type=="vector") + { + mVF=NULL; + if (mVectorReader) { + delete mVectorReader; + mVectorReader=NULL; + } + } +} + +void vvSlicerManager::RemoveActors() +{ + ///This method leaks a few objects. See RemoveActor for what a correct implementation would look like + for ( unsigned int i = 0; i < mSlicers.size(); i++) + { + mSlicers[i]->SetDisplayMode(0); + mSlicers[i]->GetRenderer()->RemoveActor(mSlicers[i]->GetImageActor()); + } +} + +void vvSlicerManager::UpdateInfoOnCursorPosition(int slicer) +{ +// int view = mSlicers[slicer]->GetSliceOrientation(); +// int slice = mSlicers[slicer]->GetSlice(); + double x = mSlicers[slicer]->GetCursorPosition()[0]; + double y = mSlicers[slicer]->GetCursorPosition()[1]; + double z = mSlicers[slicer]->GetCursorPosition()[2]; + double X = (x - mSlicers[slicer]->GetInput()->GetOrigin()[0])/ + mSlicers[slicer]->GetInput()->GetSpacing()[0]; + double Y = (y - mSlicers[slicer]->GetInput()->GetOrigin()[1])/ + mSlicers[slicer]->GetInput()->GetSpacing()[1]; + double Z = (z - mSlicers[slicer]->GetInput()->GetOrigin()[2])/ + mSlicers[slicer]->GetInput()->GetSpacing()[2]; + double value = -VTK_DOUBLE_MAX; + int displayVec = 0; + double xVec=0, yVec=0, zVec=0, valueVec=0; + int displayOver = 0; + int displayFus = 0; + double valueOver=0, valueFus=0; + if (X >= mSlicers[slicer]->GetInput()->GetWholeExtent()[0] && + X <= mSlicers[slicer]->GetInput()->GetWholeExtent()[1] && + Y >= mSlicers[slicer]->GetInput()->GetWholeExtent()[2] && + Y <= mSlicers[slicer]->GetInput()->GetWholeExtent()[3] && + Z >= mSlicers[slicer]->GetInput()->GetWholeExtent()[4] && + Z <= mSlicers[slicer]->GetInput()->GetWholeExtent()[5]) + { + value = mSlicers[slicer]->GetInput()->GetScalarComponentAsDouble( + (int)floor(X), + (int)floor(Y), + (int)floor(Z),0); + if (mSlicers[slicer]->GetVFActor() && mSlicers[slicer]->GetVFActor()->GetVisibility()) + { + displayVec = 1; + unsigned int currentTime = mSlicers[slicer]->GetTSlice(); + vtkImageData *vf = NULL; + + if (mSlicers[slicer]->GetVF()->GetVTKImages().size() > currentTime) + vf = mSlicers[slicer]->GetVF()->GetVTKImages()[currentTime]; + else + vf = mSlicers[slicer]->GetVF()->GetVTKImages()[0]; + + if (vf) + { + double Xvf = (x - vf->GetOrigin()[0])/ vf->GetSpacing()[0]; + double Yvf = (y - vf->GetOrigin()[1])/ vf->GetSpacing()[1]; + double Zvf = (z - vf->GetOrigin()[2])/ vf->GetSpacing()[2]; + xVec = vf->GetScalarComponentAsDouble( (int)floor(Xvf), (int)floor(Yvf), (int)floor(Zvf),0); + yVec = vf->GetScalarComponentAsDouble( (int)floor(Xvf), (int)floor(Yvf), (int)floor(Zvf),1); + zVec = vf->GetScalarComponentAsDouble( (int)floor(Xvf), (int)floor(Yvf), (int)floor(Zvf),2); + valueVec = sqrt(xVec*xVec + yVec*yVec + zVec*zVec); + } + } + if (mSlicers[slicer]->GetOverlayActor() && mSlicers[slicer]->GetOverlayActor()->GetVisibility()) + { + displayOver = 1; + double Xover = (x - mSlicers[slicer]->GetOverlay()->GetOrigin()[0]) + /mSlicers[slicer]->GetOverlay()->GetSpacing()[0]; + double Yover = (y - mSlicers[slicer]->GetOverlay()->GetOrigin()[1]) + /mSlicers[slicer]->GetOverlay()->GetSpacing()[1]; + double Zover = (z - mSlicers[slicer]->GetOverlay()->GetOrigin()[2]) + /mSlicers[slicer]->GetOverlay()->GetSpacing()[2]; + if (Xover >= mSlicers[slicer]->GetOverlayMapper()->GetInput()->GetWholeExtent()[0] && + Xover <= mSlicers[slicer]->GetOverlayMapper()->GetInput()->GetWholeExtent()[1] && + Yover >= mSlicers[slicer]->GetOverlayMapper()->GetInput()->GetWholeExtent()[2] && + Yover <= mSlicers[slicer]->GetOverlayMapper()->GetInput()->GetWholeExtent()[3] && + Zover >= mSlicers[slicer]->GetOverlayMapper()->GetInput()->GetWholeExtent()[4] && + Zover <= mSlicers[slicer]->GetOverlayMapper()->GetInput()->GetWholeExtent()[5]) + { + valueOver = static_cast(mSlicers[slicer]->GetOverlayMapper()->GetInput())-> + GetScalarComponentAsDouble( + (int)floor(Xover), + (int)floor(Yover), + (int)floor(Zover),0); + } + } + if (mSlicers[slicer]->GetFusionActor() && mSlicers[slicer]->GetFusionActor()->GetVisibility()) + { + displayFus = 1; + double Xfus = (x - mSlicers[slicer]->GetFusion()->GetOrigin()[0]) + /mSlicers[slicer]->GetFusion()->GetSpacing()[0]; + double Yfus = (y - mSlicers[slicer]->GetFusion()->GetOrigin()[1]) + /mSlicers[slicer]->GetFusion()->GetSpacing()[1]; + double Zfus = (z - mSlicers[slicer]->GetFusion()->GetOrigin()[2]) + /mSlicers[slicer]->GetFusion()->GetSpacing()[2]; + if (Xfus >= mSlicers[slicer]->GetFusionMapper()->GetInput()->GetWholeExtent()[0] && + Xfus <= mSlicers[slicer]->GetFusionMapper()->GetInput()->GetWholeExtent()[1] && + Yfus >= mSlicers[slicer]->GetFusionMapper()->GetInput()->GetWholeExtent()[2] && + Yfus <= mSlicers[slicer]->GetFusionMapper()->GetInput()->GetWholeExtent()[3] && + Zfus >= mSlicers[slicer]->GetFusionMapper()->GetInput()->GetWholeExtent()[4] && + Zfus <= mSlicers[slicer]->GetFusionMapper()->GetInput()->GetWholeExtent()[5]) + { + valueFus = static_cast(mSlicers[slicer]->GetFusionMapper()->GetInput())-> + GetScalarComponentAsDouble( + (int)floor(Xfus), + (int)floor(Yfus), + (int)floor(Zfus),0); + } + } + emit UpdatePosition(mSlicers[slicer]->GetCursorVisibility(), + x,y,z,X,Y,Z,value); + emit UpdateVector(displayVec,xVec, yVec, zVec, valueVec); + emit UpdateOverlay(displayOver,valueOver,value); + emit UpdateFusion(displayFus,valueFus); + for (unsigned int i = 0; i < mSlicers.size(); i++) + { + if (mSlicers[i]->GetImageActor()->GetVisibility() == 1) + emit UpdateWindows(i,mSlicers[i]->GetSliceOrientation(),mSlicers[i]->GetSlice()); + else + emit UpdateWindows(i,-1,-1); + } + } +} + +void vvSlicerManager::Activated() +{ + emit currentImageChanged(mId); +} + +void vvSlicerManager::UpdateWindowLevel() +{ + emit WindowLevelChanged(mSlicers[0]->GetColorWindow(),mSlicers[0]->GetColorLevel(),mPreset,mColorMap); +} + +void vvSlicerManager::UpdateSlice(int slicer) +{ + emit UpdateSlice(slicer, mSlicers[slicer]->GetSlice()); +} + +void vvSlicerManager::UpdateTSlice(int slicer) +{ + emit UpdateTSlice(slicer,mSlicers[0]->GetTSlice()); +} + +void vvSlicerManager::UpdateSliceRange(int slicer) +{ + emit UpdateSliceRange(slicer, + mSlicers[slicer]->GetSliceRange()[0], mSlicers[slicer]->GetSliceRange()[1], + 0,mSlicers[slicer]->GetTMax()); +} + +void vvSlicerManager::SetPreset(int preset) +{ + double range[2]; + mImage->GetScalarRange(range); + //vtkLookupTable* LUT = static_cast(mSlicers[0]->GetWindowLevel()->GetLookupTable()); + double window = mSlicers[0]->GetColorWindow(); + double level = mSlicers[0]->GetColorLevel(); + + std::string component_type=mImage->GetScalarTypeAsString(); + switch (preset) + { + case 0: + if (component_type == "unsigned_char") + { + window = 255; + level = 127; + } + else if (component_type == "short") + { + window = 2000; + level = 0; + } + else + { + window = range[1] - range[0]; + level = (range[1] + range[0])* 0.5; + } + break; + case 1: + window = 2000; + level = 0; + break; + case 2: + window = 350; + level = 60; + break; + case 3: + window = 1500; + level = -500; + break; + case 4: + window = 1000; + level = 500; + break; + case 5: + window = 1; + level = 0.5; + break; + case 6: + break; + case 7: + window=1.; + level=1; + break; + } + mPreset = preset; + this->SetColorWindow(window); + this->SetColorLevel(level); + + //if (LUT) + //{ + // SetColorMap(-1); + //} +} + +void vvSlicerManager::SetColorMap(int colormap) +{ + double range[2]; + range[0] = mSlicers[0]->GetInput()->GetScalarRange()[0]; + range[1] = mSlicers[0]->GetInput()->GetScalarRange()[1]; + + double window = mSlicers[0]->GetWindowLevel()->GetWindow(); + double level = mSlicers[0]->GetWindowLevel()->GetLevel(); + + vtkLookupTable* LUT = static_cast(mSlicers[0]->GetWindowLevel()->GetLookupTable()); + switch (colormap) + { + case -1: + if (LUT) + LUT->SetTableRange(level-fabs(window)/4,level+fabs(window)/4); + break; + case 0: + LUT = NULL; + break; + case 1: + if (LUT == NULL) + LUT = vtkLookupTable::New(); + LUT->SetTableRange(level-fabs(window)/4,level+fabs(window)/4); + LUT->SetValueRange(0,1); + LUT->SetSaturationRange(1,1); + LUT->SetHueRange(0,0.18); + break; + case 2: + if (LUT == NULL) + LUT = vtkLookupTable::New(); + LUT->SetTableRange(level-fabs(window)/4,level+fabs(window)/4); + LUT->SetValueRange(0,1); + LUT->SetSaturationRange(1,1); + LUT->SetHueRange(0.4,0.80); + break; + case 3: + if (LUT == NULL) + LUT = vtkLookupTable::New(); + LUT->SetTableRange(level-fabs(window)/4,level+fabs(window)/4); + LUT->SetValueRange(0,1); + LUT->SetSaturationRange(1,1); + LUT->SetHueRange(0,1); + break; + case 5: + if (LUT == NULL) + LUT = vtkLookupTable::New(); + LUT->SetValueRange(0.,1); + LUT->SetSaturationRange(1,1); + LUT->SetHueRange(1,0.1); + //LUT->SetRampToLinear(); + break; + } + if (LUT) + LUT->Build(); + vtkLookupTable* fusLUT = NULL; + if (mSlicers[0]->GetFusion()) + { + fusLUT = vtkLookupTable::New(); + double fusRange [2]; + fusRange[0] = mFusionLevel - mFusionWindow/2; + fusRange[1] = mFusionLevel + mFusionWindow/2; + fusLUT->SetTableRange(fusRange[0],fusRange[1]); + fusLUT->SetValueRange(1,1); + fusLUT->SetSaturationRange(1,1); + if (mFusionColorMap == 1) + fusLUT->SetHueRange(0,0.18); + else if (mFusionColorMap == 2) + fusLUT->SetHueRange(0.4,0.80); + else if (mFusionColorMap == 3) + fusLUT->SetHueRange(0,1); + fusLUT->Build(); + if (mFusionColorMap == 0) + fusLUT = NULL; + } + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + if (mSlicers[i]->GetOverlay() && mSlicers[i]->GetOverlayActor()->GetVisibility()) { + vtkLookupTable* supLUT = vtkLookupTable::New(); + supLUT->SetTableRange(range[0],range[1]); + supLUT->SetValueRange(1,1); + supLUT->SetSaturationRange(1,1); + supLUT->SetHueRange(double(mOverlayColor)/360,double(mOverlayColor)/360); + supLUT->Build(); + vtkLookupTable* invLUT = vtkLookupTable::New(); + invLUT->SetTableRange(range[0],range[1]); + invLUT->SetValueRange(1,1); + invLUT->SetSaturationRange(1,1); + invLUT->SetHueRange(double((mOverlayColor+180)%360)/360,double((mOverlayColor+180)%360)/360); + invLUT->Build(); + dynamic_cast(mSlicers[i]->GetWindowLevel()) + ->SetWindowLevelMode(true); + mSlicers[i]->GetWindowLevel()->SetLookupTable(supLUT); + mSlicers[i]->GetOverlayMapper()->SetLookupTable(invLUT); + invLUT->Delete(); + supLUT->Delete(); + } + else if (mSlicers[i]->GetOverlay()) + { + dynamic_cast(mSlicers[i]->GetWindowLevel()) + ->SetWindowLevelMode(false); + mSlicers[i]->GetWindowLevel()->SetLookupTable(NULL); + } + else + { + mSlicers[i]->GetWindowLevel()->SetLookupTable(LUT); + } + if (mSlicers[i]->GetFusion() && mSlicers[i]->GetFusionActor()->GetVisibility()) + { + mSlicers[i]->GetFusionActor()->SetOpacity(double(mFusionOpacity)/100); + mSlicers[i]->GetFusionMapper()->SetLookupTable(fusLUT); + } + } + if (fusLUT) + fusLUT->Delete(); + if (colormap >= 0) + mColorMap = colormap; +} + +vvLandmarks* vvSlicerManager::GetLandmarks() +{ + if (mLandmarks == NULL) + { + mLandmarks = new vvLandmarks(mSlicers[0]->GetTMax()+1); + for (unsigned int i = 0; i < mSlicers.size(); i++) + mSlicers[i]->SetLandmarks(mLandmarks); + } + return mLandmarks; +} + +void vvSlicerManager::AddLandmark(float x,float y,float z,float t) +{ + double x_index = (x - mSlicers[0]->GetInput()->GetOrigin()[0])/mSlicers[0]->GetInput()->GetSpacing()[0]; + double y_index = (y - mSlicers[0]->GetInput()->GetOrigin()[1])/mSlicers[0]->GetInput()->GetSpacing()[1]; + double z_index = (z - mSlicers[0]->GetInput()->GetOrigin()[2])/mSlicers[0]->GetInput()->GetSpacing()[2]; + double value = mSlicers[0]->GetInput()->GetScalarComponentAsDouble( + (int)x_index, + (int)y_index, + (int)z_index,0); + this->GetLandmarks()->AddLandmark(x,y,z,t,value); + emit LandmarkAdded(); +} diff --git a/vv/vvSlicerManager.h b/vv/vvSlicerManager.h new file mode 100644 index 0000000..2007f78 --- /dev/null +++ b/vv/vvSlicerManager.h @@ -0,0 +1,258 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvSlicerManager.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:58 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvSlicerManager_h +#define vvSlicerManager_h + +// std +#include +#include +#include + +// QT +#include + +// VTK +#include +class vtkImageData; +class vtkInteractorStyle; +class vtkRenderWindow; +class vtkPolyData; + +// VV +#include "vvConstants.h" +#include "clitkCommon.h" +#include "vvImage.h" +#include "vvMesh.h" +class vvSlicer; +class vvInteractorStyleNavigator; +class vvImageReader; +class vvImageReader; +class vvLandmarks; + +class vvSlicerManager : public QObject { + Q_OBJECT + +public: + vvSlicerManager(int numberOfSlicers); + ~vvSlicerManager(); + + std::string GetLastError() { + return mLastError; + } + + bool SetImage(std::string filename,LoadedImageType type); + void SetImage(vvImage::Pointer image); + void SetExtractedImage(std::string filename, vvImage::Pointer image, int slice); + bool SetImages(std::vector filenames,LoadedImageType type); + + bool SetOverlay(std::string filename, int dim, std::string component); + bool SetFusion(std::string filename, int dim, std::string component); + ///Set a VF by loading it from the disk + bool SetVF(std::string filename); + ///Set a VF from memory + bool SetVF(vvImage::Pointer vf,std::string filename); + ///Add a mesh to the slicers, with optional propagation using a vector field + void AddContour(vvMesh::Pointer ,bool propagate=false); + ///Toggle temporal superposition of contours + void ToggleContourSuperposition(); + + std::string GetFileName() { + return mFileName; + } + std::string GetVFName() { + return mVFName; + } + std::string GetOverlayName() { + return mOverlayName; + } + std::string GetFusionName() { + return mFusionName; + } + + ///Switch between nearest neighbor and linear interpolation + void ToggleInterpolation(); + vvSlicer* GetSlicer(int i); + void UpdateSlicer(int num, bool state); + void SetSlicerWindow(int i, vtkRenderWindow* RW); + void SetInteractorStyleNavigator(int i,vtkInteractorStyle* style); + int NumberOfSlicers() { + return mSlicers.size(); + } + vvImage::Pointer GetImage() { + return mImage; + } + vvImage::Pointer GetVF() { + return mVF; + } + int GetDimension() { + if (mImage) return mImage->GetNumberOfDimensions(); + else return -1; + } + + int GetType() { + return mType; + } + + void SetId(std::string id) { + mId = id; + } + std::string GetId() { + return mId; + } + + void SetFilename(std::string f) { + mFileName = f; + } + + void SetTSlice(int slice); + void SetNextTSlice(int originating_slicer); + void SetPreviousTSlice(int originating_slicer); + void SetTSliceInSlicer(int tslice, int slicer); + + void GenerateDefaultLookupTable(); + void SetColorWindow(double s); + void SetColorLevel(double s); + void SetOpacity(int i, double factor); + void SetColorMap(int colormap); + void SetPreset(int preset); + void SetOverlayColor(int color) { + mOverlayColor = color; + } + void SetFusionOpacity(int opacity) { + mFusionOpacity = opacity; + } + void SetFusionColorMap(int colorMap) { + mFusionColorMap = colorMap; + } + void SetFusionWindow(int window) { + mFusionWindow = window; + } + void SetFusionLevel(int level) { + mFusionLevel = level; + } + + double GetColorWindow(); + double GetColorLevel(); + int GetColorMap() { + return mColorMap; + } + int GetPreset() { + return mPreset; + } + int GetOverlayColor() { + return mOverlayColor; + } + + int GetFusionOpacity() { + return mFusionOpacity; + } + int GetFusionColorMap() { + return mFusionColorMap; + } + double GetFusionWindow() { + return mFusionWindow; + } + double GetFusionLevel() { + return mFusionLevel; + } + + void SetCursorVisibility(int s); + void UpdateViews(int current, int slicer); + void UpdateLinked(int slicer); + void Render(); + + void AddLink(std::string newId) { + mLinkedId.push_back(newId); + } + void RemoveLink(std::string oldId) { + mLinkedId.remove(oldId); + } + + ///Remove the actor defined by its type and index (example: 3rd contour) + void RemoveActor(const std::string& actor_type, int overlay_index); + void RemoveActors(); + void Reload(); + void ReloadVF(); + + void Activated(); + void UpdateInfoOnCursorPosition(int slicer); + void UpdateWindowLevel(); + void UpdateSlice(int slicer); + void UpdateTSlice(int slicer); + void UpdateSliceRange(int slicer); + + vvLandmarks *GetLandmarks(); + void AddLandmark(float x,float y,float z,float t); + +signals : + void currentImageChanged(std::string id); + void UpdatePosition(int visibility,double x, double y, double z, double X, double Y, double Z, double value); + void UpdateVector(int display, double x, double y, double z, double value); + void UpdateOverlay(int display, double valueOver, double valueRef); + void UpdateFusion(int display, double valueFus); + void UpdateWindows(int slicer, int view, int slice); + void UpdateSlice(int slicer, int slice); + void UpdateTSlice(int slicer, int slice); + void UpdateSliceRange(int slice, int min, int max, int tmin, int tmax); + void WindowLevelChanged(double window, double level, int preset, int colormap); + void UpdateLinkManager(std::string, int slicer, double x, double y, double z, int temps); + void LandmarkAdded(); + +protected: + std::vector mSlicers; + vvImageReader* mReader; + vvImageReader* mOverlayReader; + vvImageReader* mFusionReader; + vvImage::Pointer mImage; + vvImage::Pointer mVF; + vvImageReader* mVectorReader; + int mColorMap; + int mOverlayColor; + + int mFusionOpacity; + int mFusionColorMap; + double mFusionWindow; + double mFusionLevel; + + int mPreset; + LoadedImageType mType; + std::string mVFComponent; + std::string mOverlayComponent; + std::string mFusionComponent; + std::string mFileName; + std::string mId; + std::string mVFName; + std::string mOverlayName; + std::string mFusionName; + std::string mVFId; + std::string mLastError; + std::list mLinkedId; + + vvLandmarks* mLandmarks; +}; + +#endif diff --git a/vv/vvSlicerManagerCommand.cxx b/vv/vvSlicerManagerCommand.cxx new file mode 100644 index 0000000..e109b6d --- /dev/null +++ b/vv/vvSlicerManagerCommand.cxx @@ -0,0 +1,566 @@ +/*========================================================================= + +Program: vv +Module: $RCSfile: vvSlicerManagerCommand.cxx,v $ +Language: C++ +Date: $Date: 2010/01/06 13:31:57 $ +Version: $Revision: 1.1 $ +Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#include "vvSlicerManagerCommand.h" +#include "vvSlicerManager.h" + +#include "vtkTextProperty.h" +#include "vtkRenderer.h" +#include "vtkImageActor.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkPropPicker.h" +#include "vtkCamera.h" +#include "vtkImageMapToWindowLevelColors.h" +#include "vtkLookupTable.h" +#include "vtkMath.h" +#include "vtkAbstractPropPicker.h" +#include "vtkAssemblyPath.h" +#include "vtkCornerAnnotation.h" +#include + +#include "vvSlicer.h" +#include "vvInteractorStyleNavigator.h" + +#include + +vvSlicerManagerCallback::vvSlicerManagerCallback() +{ + mStartSlicer = -1; +} + +//return the num of the current slicer if visible (-1 else) +int vvSlicerManagerCallback::FindSlicerNumber(vtkRenderWindow* renwin) +{ + for (int i = 0; i < SM->NumberOfSlicers(); i++) + { + if (SM->GetSlicer(i)->GetRenderWindow() == renwin + && SM->GetSlicer(i)->GetRenderer()->GetDraw()) + { + return i; + } + } + return -1; +} + +void vvSlicerManagerCallback::Execute(vtkObject *caller, + unsigned long event, + void *vtkNotUsed(callData)) +{ + //KeyPress event + vvInteractorStyleNavigator *isi = + dynamic_cast(caller); + if (isi) + { + double x = isi->GetInteractor()->GetEventPosition()[0]; + double y = isi->GetInteractor()->GetEventPosition()[1]; + double z; + + int VisibleInWindow = this->FindSlicerNumber(isi->GetInteractor()->GetRenderWindow()); + vtkRenderer* renderer=NULL; + if (VisibleInWindow>-1) + renderer=this->SM->GetSlicer(VisibleInWindow)->GetRenderer(); + newLandmark = false; + + if (event == vtkCommand::StartPickEvent && VisibleInWindow == -1) + { + for (int i = 0; i < this->SM->NumberOfSlicers(); i++) + { + if (this->SM->GetSlicer(i)->GetCursorVisibility()) + { + this->SM->GetSlicer(i)->SetCursorVisibility(0); + this->SM->GetSlicer(i)->Render(); + } + } + } + if ( VisibleInWindow > -1 ) + { + if (event == vtkCommand::KeyPressEvent) + { + std::string KeyPress = isi->GetInteractor()->GetKeySym(); + if (KeyPress == "f" || KeyPress == "F") + { + FlyToPosition(isi->GetInteractor(),this->SM->GetSlicer(VisibleInWindow)); + } + if (KeyPress == "0") + { + this->SM->SetPreset(0); + this->SM->UpdateWindowLevel(); + return; + } + if (KeyPress == "1") + { + this->SM->SetPreset(1); + this->SM->UpdateWindowLevel(); + return; + } + if (KeyPress == "2") + { + this->SM->SetPreset(2); + this->SM->UpdateWindowLevel(); + + return; + } + if (KeyPress == "3") + { + this->SM->SetPreset(3); + this->SM->UpdateWindowLevel(); + return; + } + if (KeyPress == "4") + { + this->SM->SetPreset(4); + this->SM->UpdateWindowLevel(); + return; + } + if (KeyPress == "5") + { + this->SM->SetPreset(5); + this->SM->UpdateWindowLevel(); + return; + } + if (KeyPress == "6") + { + this->SM->SetColorMap(0); + this->SM->UpdateWindowLevel(); + return; + } + if (KeyPress == "7") + { + this->SM->SetColorMap(1); + this->SM->UpdateWindowLevel(); + return; + } + if (KeyPress == "8") + { + this->SM->SetColorMap(2); + this->SM->UpdateWindowLevel(); + return; + } + if (KeyPress == "9") + { + this->SM->SetColorMap(3); + this->SM->UpdateWindowLevel(); + return; + } + if (KeyPress == "equal") //keycodes are in vtkWin32RenderWindowInteractor + { + this->SM->SetPreset(7); + //this->SM->SetColorMap(1); + this->SM->UpdateWindowLevel(); + return; + } + if (KeyPress == "minus") + { + std::cout << "KeyPress : - " << std::endl; + this->SM->SetColorWindow(-this->SM->GetColorWindow()); + this->SM->SetColorMap(-1); + this->SM->UpdateWindowLevel(); + return; + } + if (KeyPress == "u") + { + this->SM->ToggleContourSuperposition(); + this->SM->Render(); + return; + } + if (KeyPress == "i") + { + this->SM->ToggleInterpolation(); + this->SM->Render(); + return; + } + if (KeyPress == "h") + { + this->SM->SetCursorVisibility(0); + this->SM->Render(); + return; + } + if (KeyPress == "l") + { + this->SM->Reload(); + this->SM->Render(); + return; + } + if (KeyPress == "r" or KeyPress=="R") + { + this->SM->GetSlicer(VisibleInWindow)->ResetCamera(); + this->SM->GetSlicer(VisibleInWindow)->Render(); + return; + } + if (KeyPress == "g") + { + double* cursorPos = this->SM->GetSlicer(VisibleInWindow)->GetCursorPosition(); + this->SM->GetSlicer(VisibleInWindow)->SetCurrentPosition( + cursorPos[0],cursorPos[1],cursorPos[2],cursorPos[3]); + this->SM->UpdateViews(1,VisibleInWindow); + this->SM->UpdateLinked(VisibleInWindow); + return; + } + if (KeyPress == "F5") + { + this->SM->GetSlicer(VisibleInWindow)->FlipHorizontalView(); + this->SM->GetSlicer(VisibleInWindow)->Render(); + return; + } + if (KeyPress == "F6") + { + this->SM->GetSlicer(VisibleInWindow)->FlipVerticalView(); + this->SM->GetSlicer(VisibleInWindow)->Render(); + return; + } + if (KeyPress == "Up") + { + this->SM->GetSlicer(VisibleInWindow)->SetSlice(this->SM->GetSlicer(VisibleInWindow)->GetSlice()+1); + this->SM->UpdateSlice(VisibleInWindow); + this->SM->UpdateInfoOnCursorPosition(VisibleInWindow); + } + if (KeyPress == "Down") + { + this->SM->GetSlicer(VisibleInWindow)->SetSlice(this->SM->GetSlicer(VisibleInWindow)->GetSlice()-1); + this->SM->UpdateSlice(VisibleInWindow); + this->SM->UpdateInfoOnCursorPosition(VisibleInWindow); + } + if (KeyPress == "space") + { + newLandmark = true; + } + if (KeyPress == "Left") + this->SM->SetPreviousTSlice(VisibleInWindow); + if (KeyPress == "Right") + this->SM->SetNextTSlice(VisibleInWindow); + + if (KeyPress == "F1") + { + this->SM->GetSlicer(VisibleInWindow)->GetAnnotation()->SetText(2,"Sagital\n"); + this->SM->GetSlicer(VisibleInWindow)->SetSliceOrientation(0); + this->SM->UpdateSliceRange(VisibleInWindow); + this->SM->UpdateInfoOnCursorPosition(VisibleInWindow); + } + if (KeyPress == "F2") + { + this->SM->GetSlicer(VisibleInWindow)->GetAnnotation()->SetText(2,"Coronal\n"); + this->SM->GetSlicer(VisibleInWindow)->SetSliceOrientation(1); + this->SM->UpdateSliceRange(VisibleInWindow); + this->SM->UpdateInfoOnCursorPosition(VisibleInWindow); + } + if (KeyPress == "F3") + { + this->SM->GetSlicer(VisibleInWindow)->GetAnnotation()->SetText(2,"Axial\n"); + this->SM->GetSlicer(VisibleInWindow)->SetSliceOrientation(2); + this->SM->UpdateSliceRange(VisibleInWindow); + this->SM->UpdateInfoOnCursorPosition(VisibleInWindow); + } + } + + //All type of mouse events + if (event == vtkCommand::LeaveEvent) + { + this->SM->GetSlicer(VisibleInWindow)->SetCurrentPosition(-VTK_DOUBLE_MAX,-VTK_DOUBLE_MAX, + -VTK_DOUBLE_MAX,this->SM->GetSlicer(VisibleInWindow)->GetTSlice()); + this->SM->GetSlicer(VisibleInWindow)->Render(); + return; + } + + if (event == vtkCommand::StartWindowLevelEvent) + { + mStartSlicer = -1; + this->InitialWindow = this->SM->GetColorWindow(); + this->InitialLevel = this->SM->GetColorLevel(); + + if (VisibleInWindow > -1) + { + mStartSlicer = VisibleInWindow; + } + return; + } + + if (event == vtkCommand::EndWindowLevelEvent) + { + mStartSlicer = -1; + } + + } + if (VisibleInWindow > -1) + { + this->SM->Activated(); + //if(!this->SM->GetSlicer(VisibleInWindow)->GetAnnotation()->GetVisibility()) + this->SM->GetSlicer(VisibleInWindow)->GetAnnotation()->SetVisibility(1); + + if (event == vtkCommand::MouseWheelForwardEvent && !isi->GetInteractor()->GetControlKey()) + { + this->SM->GetSlicer(VisibleInWindow)->SetSlice(this->SM->GetSlicer(VisibleInWindow)->GetSlice()+1); + this->SM->UpdateSlice(VisibleInWindow); + this->SM->UpdateInfoOnCursorPosition(VisibleInWindow); + } + else if (event == vtkCommand::MouseWheelForwardEvent && isi->GetInteractor()->GetControlKey()) + { + double factor = 2; + this->Dolly(pow((double)1.1, factor),isi->GetInteractor()); + } + else if (event == vtkCommand::MouseWheelBackwardEvent && !isi->GetInteractor()->GetControlKey()) + { + this->SM->GetSlicer(VisibleInWindow)->SetSlice(this->SM->GetSlicer(VisibleInWindow)->GetSlice()-1); + this->SM->UpdateSlice(VisibleInWindow); + this->SM->UpdateInfoOnCursorPosition(VisibleInWindow); + } + else if (event == vtkCommand::MouseWheelBackwardEvent && isi->GetInteractor()->GetControlKey()) + { + double factor = -2; + this->Dolly(pow((double)1.1, factor),isi->GetInteractor()); + } + double xWorld=0; double yWorld=0; double zWorld=0; + + //Move into World Coordinate + renderer->DisplayToNormalizedDisplay(x,y); + renderer->NormalizedDisplayToViewport(x,y); + renderer->ViewportToNormalizedViewport(x,y); + renderer->NormalizedViewportToView(x,y,z); + renderer->ViewToWorld(x,y,z); + switch (this->SM->GetSlicer(VisibleInWindow)->GetSliceOrientation()) + { + case vtkImageViewer2::SLICE_ORIENTATION_XY: + xWorld = x; + yWorld = y; + zWorld = this->SM->GetSlicer(VisibleInWindow)->GetSlice()* + this->SM->GetSlicer(VisibleInWindow)->GetInput()->GetSpacing()[2] + + this->SM->GetSlicer(VisibleInWindow)->GetInput()->GetOrigin()[2]; + break; + + case vtkImageViewer2::SLICE_ORIENTATION_XZ: + xWorld = x; + yWorld = this->SM->GetSlicer(VisibleInWindow)->GetSlice()* + this->SM->GetSlicer(VisibleInWindow)->GetInput()->GetSpacing()[1] + + this->SM->GetSlicer(VisibleInWindow)->GetInput()->GetOrigin()[1]; + zWorld = z; + break; + + case vtkImageViewer2::SLICE_ORIENTATION_YZ: + xWorld = this->SM->GetSlicer(VisibleInWindow)->GetSlice()* + this->SM->GetSlicer(VisibleInWindow)->GetInput()->GetSpacing()[0] + + this->SM->GetSlicer(VisibleInWindow)->GetInput()->GetOrigin()[0]; + yWorld = y; + zWorld = z; + break; + } + this->SM->GetSlicer(VisibleInWindow)->SetCurrentPosition(xWorld,yWorld,zWorld, + this->SM->GetSlicer(VisibleInWindow)->GetTSlice()); + if (newLandmark) + { + this->SM->AddLandmark(xWorld,yWorld,zWorld, + this->SM->GetSlicer(VisibleInWindow)->GetTSlice()); + this->SM->GetSlicer(VisibleInWindow)->UpdateLandmarks(); + this->SM->Render(); + } + if (event == vtkCommand::PickEvent || event == vtkCommand::StartPickEvent) + { + this->SM->UpdateViews(1,VisibleInWindow); + this->SM->UpdateLinked(VisibleInWindow); + this->SM->UpdateInfoOnCursorPosition(VisibleInWindow); + } + else + { + this->SM->GetSlicer(VisibleInWindow)->Render(); + } + //this->SM->GetSlicer(VisibleInWindow)->SetCurrentPosition(-VTK_DOUBLE_MAX,-VTK_DOUBLE_MAX, + //-VTK_DOUBLE_MAX,this->SM->GetSlicer(VisibleInWindow)->GetTSlice()); + //this->SM->GetSlicer(VisibleInWindow)->Render(); + } + + if (event == vtkCommand::WindowLevelEvent && mStartSlicer > -1) + { + this->SM->GetSlicer(mStartSlicer)->GetAnnotation()->SetVisibility(1); + // Adjust the window level here + int *size = isi->GetInteractor()->GetRenderWindow()->GetSize(); + double window = this->InitialWindow; + double level = this->InitialLevel; + double range[2]; + this->SM->GetImage()->GetScalarRange(range); + + // Compute normalized delta + double dx = static_cast(isi->GetWindowLevelCurrentPosition()[0] - + isi->GetWindowLevelStartPosition()[0]) / size[0]; + double dy = static_cast(isi->GetWindowLevelStartPosition()[1] - + isi->GetWindowLevelCurrentPosition()[1]) / size[1]; + //Window is exponential in nature, use exponential to avoid falling into negative numbers + dx = std::exp(1.0 * (dx*fabs(dx) + dx)) ; //Quadratic behavior for more reactive interface + dy = 0.15 * (dy*fabs(dy) + dy) * (range[1]-range[0]);//Quadratic behavior for more reactive interface + + this->SM->SetColorWindow(window*dx); + this->SM->SetColorLevel(level-dy); + this->SM->SetPreset(6); + this->SM->UpdateWindowLevel(); + this->SM->Render(); + return; + } + } +} + +void vvSlicerManagerCallback::Dolly(double factor, vtkRenderWindowInteractor *interactor) +{ + int VisibleInWindow = this->FindSlicerNumber(interactor->GetRenderWindow()); + vtkRenderer* renderer; + if (VisibleInWindow>-1) + renderer=this->SM->GetSlicer(VisibleInWindow)->GetRenderer(); + else + { + return; + } + + double viewFocus[4],viewPoint[4],motionVector[3], focalDepth; + double oldPos[3], newPos[3], distance[2]; + vtkCamera *camera = renderer->GetActiveCamera(); + camera->GetFocalPoint(viewFocus); + + renderer->SetWorldPoint(viewFocus[0], viewFocus[0], viewFocus[0], 1.0); + renderer->WorldToDisplay(); + renderer->GetDisplayPoint(viewFocus); + + focalDepth = viewFocus[2]; + + oldPos[0] = renderer->GetCenter()[0]; + oldPos[1] = renderer->GetCenter()[1]; + oldPos[2] = focalDepth; + + distance[0] = 1/factor* + (interactor->GetEventPosition()[0]-renderer->GetCenter()[0]); + distance[1] = 1/factor* + (interactor->GetEventPosition()[1]-renderer->GetCenter()[1]); + + newPos[0] = interactor->GetEventPosition()[0] - distance[0]; + newPos[1] = interactor->GetEventPosition()[1] - distance[1]; + newPos[2] = focalDepth; + + renderer->DisplayToNormalizedDisplay(oldPos[0],oldPos[1]); + renderer->NormalizedDisplayToViewport(oldPos[0],oldPos[1]); + renderer->ViewportToNormalizedViewport(oldPos[0],oldPos[1]); + renderer->NormalizedViewportToView(oldPos[0],oldPos[1],oldPos[2]); + renderer->ViewToWorld(oldPos[0],oldPos[1],oldPos[2]); + + renderer->DisplayToNormalizedDisplay(newPos[0],newPos[1]); + renderer->NormalizedDisplayToViewport(newPos[0],newPos[1]); + renderer->ViewportToNormalizedViewport(newPos[0],newPos[1]); + renderer->NormalizedViewportToView(newPos[0],newPos[1],newPos[2]); + renderer->ViewToWorld(newPos[0],newPos[1],newPos[2]); + + motionVector[0] = newPos[0] - oldPos[0]; + motionVector[1] = newPos[1] - oldPos[1]; + motionVector[2] = newPos[2] - oldPos[2]; + + camera->GetFocalPoint(viewFocus); + camera->GetPosition(viewPoint); + camera->SetFocalPoint(motionVector[0] + viewFocus[0], + motionVector[1] + viewFocus[1], + motionVector[2] + viewFocus[2]); + + camera->SetPosition(motionVector[0] + viewPoint[0], + motionVector[1] + viewPoint[1], + motionVector[2] + viewPoint[2]); + + if (camera->GetParallelProjection()) + { + camera->SetParallelScale(camera->GetParallelScale() / factor); + } + else + { + camera->Dolly(factor); + } + + if (interactor->GetLightFollowCamera()) + { + renderer->UpdateLightsGeometryToFollowCamera(); + } + renderer->ResetCameraClippingRange(); + //interactor->Render(); +} + +void vvSlicerManagerCallback::FlyToPosition(vtkRenderWindowInteractor *interactor,vvSlicer* slicer) +{ + double flyFrom[3], flyTo[3]; + double d[3], focalPt[3], position[3], positionFrom[3]; + int i, j; + int VisibleInWindow = this->FindSlicerNumber(interactor->GetRenderWindow()); + vtkRenderer* renderer=NULL; + if (VisibleInWindow>-1) + renderer=this->SM->GetSlicer(VisibleInWindow)->GetRenderer(); + else + return; + + interactor->GetPicker()->Pick(interactor->GetEventPosition()[0], + interactor->GetEventPosition()[1], 0.0, + renderer); + + vtkAssemblyPath *path=NULL; + vtkAbstractPropPicker *picker; + if ( (picker=vtkAbstractPropPicker::SafeDownCast(interactor->GetPicker()))) + { + path = picker->GetPath(); + } + if ( path != NULL ) + { + flyTo[0] = picker->GetPickPosition()[0]; + flyTo[1] = picker->GetPickPosition()[1]; + flyTo[2] = picker->GetPickPosition()[2]; + renderer->GetActiveCamera()->GetFocalPoint(flyFrom); + renderer->GetActiveCamera()->GetPosition(positionFrom); + + switch (slicer->GetSliceOrientation()) + { + case vtkImageViewer2::SLICE_ORIENTATION_XY: + flyTo[2] = flyFrom[2]; + break; + + case vtkImageViewer2::SLICE_ORIENTATION_XZ: + flyTo[1] = flyFrom[1]; + break; + + case vtkImageViewer2::SLICE_ORIENTATION_YZ: + flyTo[0] = flyFrom[0]; + break; + } + + + for (i=0; i<3; i++) + { + d[i] = flyTo[i] - flyFrom[i]; + } + double distance = vtkMath::Normalize(d); + double delta = distance/15; + + for (i=1; i<=15; i++) + { + for (j=0; j<3; j++) + { + focalPt[j] = flyFrom[j] + d[j]*i*delta; + position[j] = positionFrom[j] + d[j]*i*delta; + } + renderer->GetActiveCamera()->SetFocalPoint(focalPt); + renderer->GetActiveCamera()->SetPosition(position); + renderer->GetActiveCamera()->Dolly(0.3/15 + 1.0); + renderer->ResetCameraClippingRange(); + interactor->Render(); + } + } +} diff --git a/vv/vvSlicerManagerCommand.h b/vv/vvSlicerManagerCommand.h new file mode 100644 index 0000000..7ce9c50 --- /dev/null +++ b/vv/vvSlicerManagerCommand.h @@ -0,0 +1,74 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvSlicerManagerCommand.h,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:57 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef __vvSlicerManagerCommand_h +#define __vvSlicerManagerCommand_h + +#include "vtkCommand.h" +#include "vvSlicerManager.h" +#include "vtkRenderWindow.h" +#include "vtkRenderer.h" +#include "vtkImageData.h" +#include "vtkImageActor.h" +#include "vvInteractorStyleNavigator.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkInteractorStyleImage.h" +#include "vtkPropPicker.h" + +#include +#include +#include + +class vvSlicerManagerCallback : public vtkCommand +{ +public: + static vvSlicerManagerCallback *New() { + return new vvSlicerManagerCallback; + } + + void Execute(vtkObject *caller, + unsigned long event, + void *vtkNotUsed(callData)); + + vvSlicerManager *SM; + void Dolly(double factor, vtkRenderWindowInteractor *interactor); + void FlyToPosition(vtkRenderWindowInteractor *interactor, vvSlicer* slicer); + +protected : + vvSlicerManagerCallback(); + ~vvSlicerManagerCallback() {} + +private: + + int FindSlicerNumber(vtkRenderWindow* renwin); + + double InitialWindow; + double InitialLevel; + int mStartSlicer; + bool newLandmark; +}; + +#endif diff --git a/vv/vvStructSelector.cxx b/vv/vvStructSelector.cxx new file mode 100644 index 0000000..f438274 --- /dev/null +++ b/vv/vvStructSelector.cxx @@ -0,0 +1,55 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#include "vvStructSelector.h" +#include +#include + +void vvStructSelector::SetStructures(StructureType structures) +{ + mStructures=structures; + for (StructureType::iterator i=structures.begin();i!=structures.end();i++) + { + std::ostringstream ss; + ss << (*i).first << ":" << (*i).second; + this->structSelectionWidget->addItem(ss.str().c_str()); + } +} + +std::vector vvStructSelector::getSelectedItems() +{ + std::vector result; + for (int i=0;icount();i++) + { + if (structSelectionWidget->item(i)->isSelected()) + result.push_back(mStructures[i].first); + } + return result; +} + + +vvStructSelector::vvStructSelector() +{ + setupUi(this); +} diff --git a/vv/vvStructSelector.h b/vv/vvStructSelector.h new file mode 100644 index 0000000..f507c1e --- /dev/null +++ b/vv/vvStructSelector.h @@ -0,0 +1,52 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + Program: vv + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvStructSelector_h +#define vvStructSelector_h + +#include "ui_vvStructSelector.h" + +class vvStructSelector : public QDialog, private Ui::vvStructSelector +{ + Q_OBJECT + +public: + vvStructSelector(); + typedef std::vector > StructureType; + ///Sets the different structures and displays them + void SetStructures(StructureType structures); + ///Returns the indexes of selected ROIs + std::vector getSelectedItems(); + ///Enables the propagation checkbox + void EnablePropagationCheckBox() {this->propagateCheckBox->setEnabled(true); + this->propagateCheckBox->setChecked(true);} + ///Returns true if contours should be propagated over the sequence using the vf + bool PropagationEnabled() {return this->propagateCheckBox->isChecked();} + +protected: + StructureType mStructures; + +}; + +#endif diff --git a/vv/vvSurfaceViewerDialog.cxx b/vv/vvSurfaceViewerDialog.cxx new file mode 100644 index 0000000..f3e788b --- /dev/null +++ b/vv/vvSurfaceViewerDialog.cxx @@ -0,0 +1,175 @@ +#ifndef _vvSurfaceViewerDialog_CXX +#define _vvSurfaceViewerDialog_CXX + +/*========================================================================= + +Program: vv +Module: $RCSfile: vvSurfaceViewerDialog.cxx,v $ +Language: C++ +Date: $Date: 2010/01/06 13:31:57 $ +Version: $Revision: 1.1 $ +Author : David Sarrut (david.sarrut@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#include +#include + +#include "vvSurfaceViewerDialog.h" +#include "vtkOBJReader.h" +#include "vtkInteractorStyle.h" + + +#include "vtkPolyDataMapper.h" +#include "vtkActor.h" +#include "vtkPolyData.h" +#include "vtkRenderWindow.h" +#include "vtkRendererCollection.h" +#include "vtkRenderer.h" + +#include + +//---------------------------------------------------------------------------- +class vvManagerCallback : public vtkCommand +{ +public: + static vvManagerCallback *New() { + return new vvManagerCallback; + } + + void Execute(vtkObject *caller, + unsigned long event, + void *vtkNotUsed(callData)) + { + vtkInteractorStyle *isi = static_cast(caller); + if (isi) + { + std::string KeyPress = isi->GetInteractor()->GetKeySym(); + if (KeyPress == "Left") + { + this->IV->PreviousTime(); + } + if (KeyPress == "Right") + { + this->IV->NextTime(); + } + } + } + vvSurfaceViewerDialog *IV; +}; + + +//==================================================================== +vvSurfaceViewerDialog::vvSurfaceViewerDialog(QWidget * parent, Qt::WindowFlags f) + :QDialog(parent,f), Ui::vvSurfaceViewerDialog() { + + // initialization + setupUi(this); + + mReaders.clear(); + mMapper = NULL; + mActor = NULL; + mRenderer = NULL; + mCurrentTime = 0; + + connect(loadButton,SIGNAL(clicked()),this,SLOT(LoadSurface())); +} + +vvSurfaceViewerDialog::~vvSurfaceViewerDialog() +{ + for (unsigned int i = 0; i < mReaders.size();i++) + mReaders[i]->Delete(); + + if (mMapper) + mMapper->Delete(); + + if (mActor) + mActor->Delete(); + + if (mRenderer) + mRenderer->Delete(); +} + +void vvSurfaceViewerDialog::LoadSurface() +{ + QString Extensions = "All Files (*)"; + Extensions += ";;Surface ( *.vtk)"; + QStringList files = QFileDialog::getOpenFileNames(this,tr("Load Surfaces"),tr(""),Extensions); + if (files.isEmpty()) + return; + + if (!mMapper) + { + mMapper = vtkPolyDataMapper::New(); + } + + for (int i = 0; i < files.size(); i++) + { + vtkOBJReader* reader = vtkOBJReader::New(); + reader->SetFileName(files[i].toStdString().c_str()); + reader->Update(); + mReaders.push_back(reader); + } + + mMapper->SetInput(mReaders[mCurrentTime]->GetOutput()); + + if (!mActor) + { + mActor = vtkActor::New(); + mActor->SetMapper(mMapper); + } + if (!mRenderer) + { + mRenderer = vtkRenderer::New(); + mRenderer->AddActor(mActor); + renderWidget->GetRenderWindow()->AddRenderer(mRenderer); + } + + mRenderer->ResetCamera(); + renderWidget->GetRenderWindow()->Render(); + + vvManagerCallback *smc = vvManagerCallback::New(); + smc->IV = this; + + if (renderWidget->GetRenderWindow()->GetInteractor()) + renderWidget->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::KeyPressEvent, smc); + //readHeader->Delete(); +} + +void vvSurfaceViewerDialog::NextTime() +{ + mCurrentTime++; + if (mCurrentTime >= mReaders.size()) + mCurrentTime = 0; + mMapper->SetInput(mReaders[mCurrentTime]->GetOutput()); + mMapper->Modified(); + renderWidget->GetRenderWindow()->Render(); +} + +void vvSurfaceViewerDialog::PreviousTime() +{ + mCurrentTime--; + if (mCurrentTime < 0) + mCurrentTime = mReaders.size() - 1; + mMapper->SetInput(mReaders[mCurrentTime]->GetOutput()); + mMapper->Modified(); + renderWidget->GetRenderWindow()->Render(); +} + +#endif /* end #define _vvSurfaceViewerDialog_CXX */ diff --git a/vv/vvSurfaceViewerDialog.h b/vv/vvSurfaceViewerDialog.h new file mode 100644 index 0000000..41eff5a --- /dev/null +++ b/vv/vvSurfaceViewerDialog.h @@ -0,0 +1,66 @@ +#ifndef _vvSurfaceViewerDialog_H +#define _vvSurfaceViewerDialog_H + +/*========================================================================= + +Program: vv +Module: $RCSfile: vvSurfaceViewerDialog.h,v $ +Language: C++ +Date: $Date: 2010/01/06 13:31:57 $ +Version: $Revision: 1.1 $ +Author : David Sarrut (david.sarrut@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + + +#include "ui_vvSurfaceViewerDialog.h" + +class vtkPolyDataMapper; +class vtkActor; +class vtkOBJReader; + +#include +#include + +//==================================================================== +class vvSurfaceViewerDialog : public QDialog, private Ui::vvSurfaceViewerDialog { + + Q_OBJECT + +public: + // constructor - destructor + vvSurfaceViewerDialog(QWidget * parent=0, Qt::WindowFlags f=0); + ~vvSurfaceViewerDialog(); + void NextTime(); + void PreviousTime(); + +public slots : + void LoadSurface(); + +private : + std::vector mReaders; + vtkPolyDataMapper* mMapper; + vtkActor* mActor; + vtkRenderer * mRenderer; + unsigned int mCurrentTime; + +}; // end class vvSurfaceViewerDialog +//==================================================================== + +#endif /* end #define _vvSurfaceViewerDialog_H */ diff --git a/vv/vvTemplateFile.cxx b/vv/vvTemplateFile.cxx new file mode 100644 index 0000000..02fc9f9 --- /dev/null +++ b/vv/vvTemplateFile.cxx @@ -0,0 +1,25 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#include "vvXXX.h" diff --git a/vv/vvTemplateFile.h b/vv/vvTemplateFile.h new file mode 100644 index 0000000..98a0348 --- /dev/null +++ b/vv/vvTemplateFile.h @@ -0,0 +1,36 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + Program: vv + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvXXX_h +#define vvXXX_h + +class vvXXX +{ +public: + +protected: + +}; + +#endif diff --git a/vv/vvUtils.cxx b/vv/vvUtils.cxx new file mode 100644 index 0000000..d4d8b2c --- /dev/null +++ b/vv/vvUtils.cxx @@ -0,0 +1,65 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#include +#include +#include + +#include "clitkCommon.h" +#include "vvUtils.h" + +const std::string vv_user_file=".vv_settings.txt"; +typedef std::list FileListType; + +///Returns the last images opened by the user +FileListType GetRecentlyOpenedImages() +{ + std::ifstream in((QDir::homePath().toStdString() + "/" + vv_user_file).c_str()); + std::string current_file; + FileListType result; + in >> current_file; + while (in.good()) + { + result.push_back(current_file); + in >> current_file; + } + in.close(); + return result; +} + +///Adds an image to the list of recently opened images +void AddToRecentlyOpenedImages(std::string filename) +{ + FileListType file_list = GetRecentlyOpenedImages(); + FileListType::iterator i = std::find(file_list.begin(),file_list.end(),filename); + if (i != file_list.end()) // avoid dupes + file_list.erase(i); + while (file_list.size() >= 6) //keep list to a reasonable size + file_list.pop_back(); + file_list.push_front(filename); + std::ofstream out((QDir::homePath().toStdString() + "/" + vv_user_file).c_str(),std::ios_base::out | std::ios_base::trunc); + for (FileListType::iterator j = file_list.begin() ; j != file_list.end() ; j++) + out << (*j) << std::endl; + out.close(); +} diff --git a/vv/vvUtils.h b/vv/vvUtils.h new file mode 100644 index 0000000..58f84da --- /dev/null +++ b/vv/vvUtils.h @@ -0,0 +1,39 @@ +/*========================================================================= + + Program: vv + Language: C++ + Author : Joel Schaerer (joel.schaerer@insa-lyon.fr) + Program: vv + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ +#ifndef vvXXX_h +#define vvXXX_h + +///Utility functions that don't need to be in vvMainWindow + +#include +#include + +///Returns the last images opened by the user +std::list GetRecentlyOpenedImages(); + +///Adds an image to the list of recently opened images +void AddToRecentlyOpenedImages(std::string filename); + +#endif diff --git a/vv/vvs.cxx b/vv/vvs.cxx new file mode 100644 index 0000000..cc84d86 --- /dev/null +++ b/vv/vvs.cxx @@ -0,0 +1,63 @@ +/*========================================================================= + + Program: vv + Module: $RCSfile: vvs.cxx,v $ + Language: C++ + Date: $Date: 2010/01/06 13:31:58 $ + Version: $Revision: 1.1 $ + Author : Pierre Seroul (pierre.seroul@gmail.com) + +Copyright (C) 2008 +Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr +CREATIS-LRMN http://www.creatis.insa-lyon.fr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=========================================================================*/ + +#include + +#include "vvImageReader.h" +#include "vvMeshReader.h" +#include "vvInit.h" +#include "vvs.h" + + +int main( int argc, char** argv ) +{ + initialize_IO(); + QApplication app(argc,argv); + vvDummyWindow w; + w.show(); + return app.exec(); +} + +vvDummyWindow::vvDummyWindow() +{ + setupUi(this); +} + +void vvDummyWindow::Run() +{ + vvImageReader imr; + imr.SetInputFilename("CT_UNTAGGED2MM_0.mhd"); + imr.Update(IMAGE); + + vvMeshReader r; + r.SetImage(imr.GetOutput()); + r.SetFilename("struct.DCM"); + std::vector selected; + selected.push_back(1); + r.SetSelectedItems(selected); + r.Update(); +} diff --git a/vv/vvs.h b/vv/vvs.h new file mode 100644 index 0000000..5e4e126 --- /dev/null +++ b/vv/vvs.h @@ -0,0 +1,19 @@ +#ifndef vvs_h +#define vvs_h + +//This is a dummy executable for tests + +#include "ui_vvDummyWindow.h" +#include + +class vvDummyWindow : public QMainWindow, private Ui::vvDummyWindow +{ + Q_OBJECT +public: + vvDummyWindow(); + +public slots: + void Run(); +}; + +#endif