├── .gitignore ├── CMakeLists.txt ├── MANIFEST.in ├── README.md ├── doc ├── Makefile ├── make.bat ├── notebooks │ └── IRTK_from_Python.ipynb └── source │ ├── conf.py │ ├── images │ ├── average.png │ └── thumbnail.png │ ├── index.rst │ ├── sphinxext │ ├── LICENSE.txt │ ├── __init__.py │ ├── autosummary.py │ ├── autosummary_generate.py │ ├── docscrape.py │ ├── docscrape_sphinx.py │ ├── numpydoc.py │ └── phantom_import.py │ └── why.rst ├── generate_templates.py ├── include ├── crf.h ├── drawing.h ├── irtk2cython.h ├── reconstruction.h ├── registration.h └── voxellise.h ├── irtk ├── __init__.py ├── ext │ ├── FitEllipsoid.py │ ├── Show.py │ ├── Show3D.py │ ├── __init__.py │ ├── dicomReader.py │ ├── featExtract.ubu │ ├── opencv.py │ ├── reconstruction.py │ ├── sift3d.py │ └── vtkTools.py ├── image.py ├── registration.py ├── sitkreader.py ├── utils.py └── vtk2irtk.py ├── scripts ├── convert.py ├── decrop.py ├── find_template.py ├── flip.py ├── gcut.py ├── hull.py └── polydata2nifti.py ├── setup.py └── src ├── _irtk.pyx ├── crf.cc ├── drawing.cc ├── irtk2cython.cc ├── reconstruction.cc ├── registration.cc └── voxellise.cc /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | 3 | # Python 4 | *.py[cod] 5 | 6 | # Emacs 7 | *~ 8 | .\#* 9 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | # CMakeLists.txt adapted from 4 | # https://github.com/lantiga/cyitk 5 | 6 | #project(CYTHON) 7 | 8 | find_package(IRTK REQUIRED) 9 | INCLUDE_DIRECTORIES(${IRTK_INCLUDE_DIRS}) 10 | LINK_DIRECTORIES(${IRTK_LIBRARIES_DIR}) 11 | LINK_DIRECTORIES(/Users/kevin/anaconda/envs/_build_placehold_placehold_placehold_placehold_placeh/lib) 12 | LINK_DIRECTORIES(/Users/kevin/anaconda/envs/_build/lib/) 13 | # SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") 14 | # SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") 15 | 16 | # TBB 17 | ADD_DEFINITIONS(-DHAS_TBB) 18 | INCLUDE_DIRECTORIES(${TBB_INCLUDE_DIRS}) 19 | # LINK_DIRECTORIES(${TBB_LIBRARY_DIRS}) 20 | #LINK_LIBRARIES(${TBB_LIBRARIES}) 21 | 22 | # VTK 23 | find_package(VTK 6.0 REQUIRED NO_MODULE) 24 | include(${VTK_USE_FILE}) 25 | include_directories(${VTK_INCLUDE_DIRS}) 26 | 27 | find_package(PythonLibs REQUIRED) 28 | if(USE_PYTHONLIBS_FILE) 29 | include(${USE_PYTHONLIBS_FILE}) 30 | endif(USE_PYTHONLIBS_FILE) 31 | 32 | find_package(PythonInterp REQUIRED) 33 | if(USE_PYTHONINTERP_FILE) 34 | include(${USE_PYTHONINTERP_FILE}) 35 | endif(USE_PYTHONINTERP_FILE) 36 | 37 | #get numpy include path 38 | execute_process( 39 | COMMAND 40 | ${PYTHON_EXECUTABLE} -c "import numpy; print numpy.get_include()" 41 | OUTPUT_VARIABLE NUMPY_INCLUDE_PATH 42 | RESULT_VARIABLE NUMPY_ERR 43 | OUTPUT_STRIP_TRAILING_WHITESPACE 44 | ) 45 | if(NUMPY_ERR) 46 | message(SEND_ERROR "WARNING: NumPy header not found.") 47 | endif(NUMPY_ERR) 48 | set(PYTHON_INCLUDE_PATH ${PYTHON_INCLUDE_PATH} ${NUMPY_INCLUDE_PATH}) 49 | 50 | #TODO: Windows? Need a FindCython.cmake 51 | find_program(CYTHON_EXECUTABLE cython /usr/bin /usr/local/bin $ENV{PYTHONPATH} ~/.local/bin) 52 | 53 | #create temporary directory 54 | set(TMP_SRC_DIR ${CMAKE_BINARY_DIR}/tmp) 55 | file(MAKE_DIRECTORY ${TMP_SRC_DIR}) 56 | 57 | #generate templates 58 | execute_process( 59 | COMMAND 60 | ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/generate_templates.py ${TMP_SRC_DIR} ${CMAKE_SOURCE_DIR}/ 61 | OUTPUT_VARIABLE PYTHON_OUTPUT 62 | ERROR_VARIABLE PYTHON_ERROR 63 | RESULT_VARIABLE PYTHON_ERR 64 | ) 65 | if(PYTHON_OUTPUT) 66 | message(${PYTHON_OUTPUT}) 67 | endif(PYTHON_OUTPUT) 68 | if(PYTHON_ERR) 69 | message(SEND_ERROR ${PYTHON_ERROR}) 70 | endif(PYTHON_ERR) 71 | 72 | set( CPP_SRCS 73 | "src/registration.cc" 74 | "src/reconstruction.cc" 75 | "${TMP_SRC_DIR}/templates.cc" 76 | "src/irtk2cython.cc" 77 | "src/voxellise.cc" 78 | "src/drawing.cc" 79 | "src/crf.cc" 80 | ) 81 | 82 | include_directories(${PYTHON_INCLUDE_PATH}) 83 | include_directories("include") 84 | include_directories(${CMAKE_BINARY_DIR}"/tmp") 85 | 86 | #run cython on all pyx files 87 | execute_process( 88 | COMMAND 89 | ${CYTHON_EXECUTABLE} --cplus ${CMAKE_BINARY_DIR}/tmp/_irtk.pyx -o ${CMAKE_BINARY_DIR}/tmp/_irtk.cpp 90 | OUTPUT_VARIABLE CYTHON_OUTPUT 91 | ERROR_VARIABLE CYTHON_ERROR 92 | RESULT_VARIABLE CYTHON_ERR 93 | ) 94 | if(CYTHON_ERR) 95 | message(SEND_ERROR ${CYTHON_ERROR}) 96 | endif(CYTHON_ERR) 97 | 98 | set(CPP_SRCS ${CPP_SRCS} ${CMAKE_BINARY_DIR}/tmp/_irtk.cpp) 99 | 100 | add_library( "_irtk" MODULE ${CPP_SRCS}) 101 | target_link_libraries( "_irtk" ${IRTK_LIBRARIES} ${PYTHON_LIBRARY} ${IRTK_LIBRARIES} ${PNG_LIBRARY} znz png) 102 | set_target_properties("_irtk" PROPERTIES PREFIX "" LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/irtk) 103 | 104 | # copy all python files 105 | #file( COPY ${CMAKE_SOURCE_DIR}/irtk DESTINATION ${CMAKE_BINARY_DIR}/lib ) 106 | 107 | #file( COPY ${CMAKE_BINARY_DIR}/_irtk.so DESTINATION ${CMAKE_SOURCE_DIR}/irtk ) 108 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include irtk *.py *.so *.ubu 2 | prune build 3 | prune doc 4 | prune src 5 | prune include 6 | prune scripts 7 | exclude generate_templates.py 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | python-irtk 2 | =========== 3 | 4 | Install 5 | ------- 6 | 7 | The easiest way to install `python-irtk` is through `conda`: 8 | 9 | conda install -c kevin-keraudren python-irtk 10 | 11 | `conda` is the package manager that comes with the free Anaconda Python distribution from [Continuum Analytics](http://continuum.io/downloads). It is highly recommended for scientific computing in Python as it allows you to install within seconds your favourite libraries, along with their depencies. Additionally, you can easily set up different virtual environments in order to test different versions of some libraries. 12 | 13 | Documentation 14 | ------------- 15 | 16 | See the [documentation](http://biomedia.github.io/python-irtk/) 17 | and [notebooks](http://nbviewer.ipython.org/github/BioMedIA/python-irtk/tree/master/doc/notebooks/). 18 | 19 | To update the documentation: 20 | 21 | cd python-irtk/doc/ 22 | make html 23 | cd ../../python-irtk-doc/ 24 | git add . 25 | git commit -m "rebuilt docs" 26 | git push origin gh-pages 27 | 28 | See [daler's](http://daler.github.io/sphinxdoc-test/includeme.html) tutorial for 29 | more details on publishing sphinx-generated docs on github. 30 | 31 | For more information on IRTK: 32 | ----------------------------- 33 | 34 | See the github repository of [IRTK](https://github.com/BioMedIA/IRTK). 35 | 36 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = ../../python-irtk-doc 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | mv $(BUILDDIR)/html/_images $(BUILDDIR)/html/images 55 | mv $(BUILDDIR)/html/_sources $(BUILDDIR)/html/sources 56 | mv $(BUILDDIR)/html/_static $(BUILDDIR)/html/static 57 | perl -i -pe 's/_images/images/g' $(BUILDDIR)/html/*.html 58 | perl -i -pe 's/_sources/sources/g' $(BUILDDIR)/html/*.html 59 | perl -i -pe 's/_static/static/g' $(BUILDDIR)/html/*.html 60 | @echo 61 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 62 | 63 | dirhtml: 64 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 65 | @echo 66 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 67 | 68 | singlehtml: 69 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 70 | @echo 71 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 72 | 73 | pickle: 74 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 75 | @echo 76 | @echo "Build finished; now you can process the pickle files." 77 | 78 | json: 79 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 80 | @echo 81 | @echo "Build finished; now you can process the JSON files." 82 | 83 | htmlhelp: 84 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 85 | @echo 86 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 87 | ".hhp project file in $(BUILDDIR)/htmlhelp." 88 | 89 | qthelp: 90 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 91 | @echo 92 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 93 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 94 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/irtk.qhcp" 95 | @echo "To view the help file:" 96 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/irtk.qhc" 97 | 98 | devhelp: 99 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 100 | @echo 101 | @echo "Build finished." 102 | @echo "To view the help file:" 103 | @echo "# mkdir -p $$HOME/.local/share/devhelp/irtk" 104 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/irtk" 105 | @echo "# devhelp" 106 | 107 | epub: 108 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 109 | @echo 110 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 111 | 112 | latex: 113 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 114 | @echo 115 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 116 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 117 | "(use \`make latexpdf' here to do that automatically)." 118 | 119 | latexpdf: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through pdflatex..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | latexpdfja: 126 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 127 | @echo "Running LaTeX files through platex and dvipdfmx..." 128 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 129 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 130 | 131 | text: 132 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 133 | @echo 134 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 135 | 136 | man: 137 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 138 | @echo 139 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 140 | 141 | texinfo: 142 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 143 | @echo 144 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 145 | @echo "Run \`make' in that directory to run these through makeinfo" \ 146 | "(use \`make info' here to do that automatically)." 147 | 148 | info: 149 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 150 | @echo "Running Texinfo files through makeinfo..." 151 | make -C $(BUILDDIR)/texinfo info 152 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 153 | 154 | gettext: 155 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 156 | @echo 157 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 158 | 159 | changes: 160 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 161 | @echo 162 | @echo "The overview file is in $(BUILDDIR)/changes." 163 | 164 | linkcheck: 165 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 166 | @echo 167 | @echo "Link check complete; look for any errors in the above output " \ 168 | "or in $(BUILDDIR)/linkcheck/output.txt." 169 | 170 | doctest: 171 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 172 | @echo "Testing of doctests in the sources finished, look at the " \ 173 | "results in $(BUILDDIR)/doctest/output.txt." 174 | 175 | xml: 176 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 177 | @echo 178 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 179 | 180 | pseudoxml: 181 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 182 | @echo 183 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 184 | -------------------------------------------------------------------------------- /doc/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source 10 | set I18NSPHINXOPTS=%SPHINXOPTS% source 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | goto end 41 | ) 42 | 43 | if "%1" == "clean" ( 44 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 45 | del /q /s %BUILDDIR%\* 46 | goto end 47 | ) 48 | 49 | 50 | %SPHINXBUILD% 2> nul 51 | if errorlevel 9009 ( 52 | echo. 53 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 54 | echo.installed, then set the SPHINXBUILD environment variable to point 55 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 56 | echo.may add the Sphinx directory to PATH. 57 | echo. 58 | echo.If you don't have Sphinx installed, grab it from 59 | echo.http://sphinx-doc.org/ 60 | exit /b 1 61 | ) 62 | 63 | if "%1" == "html" ( 64 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 68 | goto end 69 | ) 70 | 71 | if "%1" == "dirhtml" ( 72 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 76 | goto end 77 | ) 78 | 79 | if "%1" == "singlehtml" ( 80 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 84 | goto end 85 | ) 86 | 87 | if "%1" == "pickle" ( 88 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can process the pickle files. 92 | goto end 93 | ) 94 | 95 | if "%1" == "json" ( 96 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 97 | if errorlevel 1 exit /b 1 98 | echo. 99 | echo.Build finished; now you can process the JSON files. 100 | goto end 101 | ) 102 | 103 | if "%1" == "htmlhelp" ( 104 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 105 | if errorlevel 1 exit /b 1 106 | echo. 107 | echo.Build finished; now you can run HTML Help Workshop with the ^ 108 | .hhp project file in %BUILDDIR%/htmlhelp. 109 | goto end 110 | ) 111 | 112 | if "%1" == "qthelp" ( 113 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 117 | .qhcp project file in %BUILDDIR%/qthelp, like this: 118 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\irtk.qhcp 119 | echo.To view the help file: 120 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\irtk.ghc 121 | goto end 122 | ) 123 | 124 | if "%1" == "devhelp" ( 125 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished. 129 | goto end 130 | ) 131 | 132 | if "%1" == "epub" ( 133 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 137 | goto end 138 | ) 139 | 140 | if "%1" == "latex" ( 141 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 145 | goto end 146 | ) 147 | 148 | if "%1" == "latexpdf" ( 149 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 150 | cd %BUILDDIR%/latex 151 | make all-pdf 152 | cd %BUILDDIR%/.. 153 | echo. 154 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 155 | goto end 156 | ) 157 | 158 | if "%1" == "latexpdfja" ( 159 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 160 | cd %BUILDDIR%/latex 161 | make all-pdf-ja 162 | cd %BUILDDIR%/.. 163 | echo. 164 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 165 | goto end 166 | ) 167 | 168 | if "%1" == "text" ( 169 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 170 | if errorlevel 1 exit /b 1 171 | echo. 172 | echo.Build finished. The text files are in %BUILDDIR%/text. 173 | goto end 174 | ) 175 | 176 | if "%1" == "man" ( 177 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 178 | if errorlevel 1 exit /b 1 179 | echo. 180 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 181 | goto end 182 | ) 183 | 184 | if "%1" == "texinfo" ( 185 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 186 | if errorlevel 1 exit /b 1 187 | echo. 188 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 189 | goto end 190 | ) 191 | 192 | if "%1" == "gettext" ( 193 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 194 | if errorlevel 1 exit /b 1 195 | echo. 196 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 197 | goto end 198 | ) 199 | 200 | if "%1" == "changes" ( 201 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 202 | if errorlevel 1 exit /b 1 203 | echo. 204 | echo.The overview file is in %BUILDDIR%/changes. 205 | goto end 206 | ) 207 | 208 | if "%1" == "linkcheck" ( 209 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 210 | if errorlevel 1 exit /b 1 211 | echo. 212 | echo.Link check complete; look for any errors in the above output ^ 213 | or in %BUILDDIR%/linkcheck/output.txt. 214 | goto end 215 | ) 216 | 217 | if "%1" == "doctest" ( 218 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 219 | if errorlevel 1 exit /b 1 220 | echo. 221 | echo.Testing of doctests in the sources finished, look at the ^ 222 | results in %BUILDDIR%/doctest/output.txt. 223 | goto end 224 | ) 225 | 226 | if "%1" == "xml" ( 227 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 228 | if errorlevel 1 exit /b 1 229 | echo. 230 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 231 | goto end 232 | ) 233 | 234 | if "%1" == "pseudoxml" ( 235 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 236 | if errorlevel 1 exit /b 1 237 | echo. 238 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 239 | goto end 240 | ) 241 | 242 | :end 243 | -------------------------------------------------------------------------------- /doc/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # irtk documentation build configuration file, created by 4 | # sphinx-quickstart on Tue Aug 13 15:16:00 2013. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | 16 | 17 | # If extensions (or modules to document with autodoc) are in another directory, 18 | # add these directories to sys.path here. If the directory is relative to the 19 | # documentation root, use os.path.abspath to make it absolute, like shown here. 20 | #sys.path.insert(0, os.path.abspath('.')) 21 | 22 | # this will fail if _irtk is not built 23 | #sys.path.insert(1,os.path.abspath('../../')) 24 | 25 | sys.path.append(os.path.abspath('./sphinxext')) 26 | 27 | # -- General configuration ----------------------------------------------------- 28 | 29 | # If your documentation needs a minimal Sphinx version, state it here. 30 | #needs_sphinx = '1.0' 31 | 32 | # Add any Sphinx extension module names here, as strings. They can be extensions 33 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 34 | extensions = ['sphinx.ext.autodoc','sphinx.ext.todo','numpydoc', 35 | 'phantom_import', 'autosummary',] 36 | 37 | # Add any paths that contain templates here, relative to this directory. 38 | templates_path = ['_templates'] 39 | 40 | # The suffix of source filenames. 41 | source_suffix = '.rst' 42 | 43 | # The encoding of source files. 44 | #source_encoding = 'utf-8-sig' 45 | 46 | # The master toctree document. 47 | master_doc = 'index' 48 | 49 | # General information about the project. 50 | project = u'irtk' 51 | copyright = u'2013, Kevin Keraudren' 52 | 53 | # The version info for the project you're documenting, acts as replacement for 54 | # |version| and |release|, also used in various other places throughout the 55 | # built documents. 56 | # 57 | # The short X.Y version. 58 | version = '1.0' 59 | # The full version, including alpha/beta/rc tags. 60 | release = '1.0' 61 | 62 | # The language for content autogenerated by Sphinx. Refer to documentation 63 | # for a list of supported languages. 64 | #language = None 65 | 66 | # There are two options for replacing |today|: either, you set today to some 67 | # non-false value, then it is used: 68 | #today = '' 69 | # Else, today_fmt is used as the format for a strftime call. 70 | #today_fmt = '%B %d, %Y' 71 | 72 | # List of patterns, relative to source directory, that match files and 73 | # directories to ignore when looking for source files. 74 | exclude_patterns = [] 75 | 76 | # The reST default role (used for this markup: `text`) to use for all documents. 77 | #default_role = None 78 | 79 | # If true, '()' will be appended to :func: etc. cross-reference text. 80 | #add_function_parentheses = True 81 | 82 | # If true, the current module name will be prepended to all description 83 | # unit titles (such as .. function::). 84 | #add_module_names = True 85 | 86 | # If true, sectionauthor and moduleauthor directives will be shown in the 87 | # output. They are ignored by default. 88 | #show_authors = False 89 | 90 | # The name of the Pygments (syntax highlighting) style to use. 91 | pygments_style = 'sphinx' 92 | 93 | # A list of ignored prefixes for module index sorting. 94 | #modindex_common_prefix = [] 95 | 96 | # If true, keep warnings as "system message" paragraphs in the built documents. 97 | #keep_warnings = False 98 | 99 | 100 | # -- Options for HTML output --------------------------------------------------- 101 | 102 | # The theme to use for HTML and HTML Help pages. See the documentation for 103 | # a list of builtin themes. 104 | html_theme = 'default' 105 | 106 | # Theme options are theme-specific and customize the look and feel of a theme 107 | # further. For a list of options available for each theme, see the 108 | # documentation. 109 | #html_theme_options = {} 110 | 111 | # Add any paths that contain custom themes here, relative to this directory. 112 | #html_theme_path = [] 113 | 114 | # The name for this set of Sphinx documents. If None, it defaults to 115 | # " v documentation". 116 | #html_title = None 117 | 118 | # A shorter title for the navigation bar. Default is the same as html_title. 119 | #html_short_title = None 120 | 121 | # The name of an image file (relative to this directory) to place at the top 122 | # of the sidebar. 123 | #html_logo = None 124 | 125 | # The name of an image file (within the static path) to use as favicon of the 126 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 127 | # pixels large. 128 | #html_favicon = None 129 | 130 | # Add any paths that contain custom static files (such as style sheets) here, 131 | # relative to this directory. They are copied after the builtin static files, 132 | # so a file named "default.css" will overwrite the builtin "default.css". 133 | html_static_path = ['_static'] 134 | 135 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 136 | # using the given strftime format. 137 | #html_last_updated_fmt = '%b %d, %Y' 138 | 139 | # If true, SmartyPants will be used to convert quotes and dashes to 140 | # typographically correct entities. 141 | #html_use_smartypants = True 142 | 143 | # Custom sidebar templates, maps document names to template names. 144 | #html_sidebars = {} 145 | 146 | # Additional templates that should be rendered to pages, maps page names to 147 | # template names. 148 | #html_additional_pages = {} 149 | 150 | # If false, no module index is generated. 151 | #html_domain_indices = True 152 | 153 | # If false, no index is generated. 154 | #html_use_index = True 155 | 156 | # If true, the index is split into individual pages for each letter. 157 | #html_split_index = False 158 | 159 | # If true, links to the reST sources are added to the pages. 160 | #html_show_sourcelink = True 161 | 162 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 163 | #html_show_sphinx = True 164 | 165 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 166 | #html_show_copyright = True 167 | 168 | # If true, an OpenSearch description file will be output, and all pages will 169 | # contain a tag referring to it. The value of this option must be the 170 | # base URL from which the finished HTML is served. 171 | #html_use_opensearch = '' 172 | 173 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 174 | #html_file_suffix = None 175 | 176 | # Output file base name for HTML help builder. 177 | htmlhelp_basename = 'irtkdoc' 178 | 179 | 180 | # -- Options for LaTeX output -------------------------------------------------- 181 | 182 | latex_elements = { 183 | # The paper size ('letterpaper' or 'a4paper'). 184 | #'papersize': 'letterpaper', 185 | 186 | # The font size ('10pt', '11pt' or '12pt'). 187 | #'pointsize': '10pt', 188 | 189 | # Additional stuff for the LaTeX preamble. 190 | #'preamble': '', 191 | } 192 | 193 | # Grouping the document tree into LaTeX files. List of tuples 194 | # (source start file, target name, title, author, documentclass [howto/manual]). 195 | latex_documents = [ 196 | ('index', 'irtk.tex', u'irtk Documentation', 197 | u'Kevin Keraudren', 'manual'), 198 | ] 199 | 200 | # The name of an image file (relative to this directory) to place at the top of 201 | # the title page. 202 | #latex_logo = None 203 | 204 | # For "manual" documents, if this is true, then toplevel headings are parts, 205 | # not chapters. 206 | #latex_use_parts = False 207 | 208 | # If true, show page references after internal links. 209 | #latex_show_pagerefs = False 210 | 211 | # If true, show URL addresses after external links. 212 | #latex_show_urls = False 213 | 214 | # Documents to append as an appendix to all manuals. 215 | #latex_appendices = [] 216 | 217 | # If false, no module index is generated. 218 | #latex_domain_indices = True 219 | 220 | 221 | # -- Options for manual page output -------------------------------------------- 222 | 223 | # One entry per manual page. List of tuples 224 | # (source start file, name, description, authors, manual section). 225 | man_pages = [ 226 | ('index', 'irtk', u'irtk Documentation', 227 | [u'Kevin Keraudren'], 1) 228 | ] 229 | 230 | # If true, show URL addresses after external links. 231 | #man_show_urls = False 232 | 233 | 234 | # -- Options for Texinfo output ------------------------------------------------ 235 | 236 | # Grouping the document tree into Texinfo files. List of tuples 237 | # (source start file, target name, title, author, 238 | # dir menu entry, description, category) 239 | texinfo_documents = [ 240 | ('index', 'irtk', u'irtk Documentation', 241 | u'Kevin Keraudren', 'irtk', 'One line description of project.', 242 | 'Miscellaneous'), 243 | ] 244 | 245 | # Documents to append as an appendix to all manuals. 246 | #texinfo_appendices = [] 247 | 248 | # If false, no module index is generated. 249 | #texinfo_domain_indices = True 250 | 251 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 252 | #texinfo_show_urls = 'footnote' 253 | 254 | # If true, do not generate a @detailmenu in the "Top" node's menu. 255 | #texinfo_no_detailmenu = False 256 | -------------------------------------------------------------------------------- /doc/source/images/average.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioMedIA/python-irtk/0ca6f94dcbe27807ce3e0c408354c47354e974bc/doc/source/images/average.png -------------------------------------------------------------------------------- /doc/source/images/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioMedIA/python-irtk/0ca6f94dcbe27807ce3e0c408354c47354e974bc/doc/source/images/thumbnail.png -------------------------------------------------------------------------------- /doc/source/index.rst: -------------------------------------------------------------------------------- 1 | .. irtk documentation master file, created by 2 | sphinx-quickstart on Tue Aug 13 15:16:00 2013. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | python-irtk documentation 7 | ========================= 8 | 9 | The aim of this module is to provide a simple and pythonic interface to IRTK 10 | (http://www.doc.ic.ac.uk/~dr/software/) by considering a medical image as a 11 | subclass of a numpy.ndarray containing information headers (dimension, 12 | orientation, origin and pixel size). By overloading ``__getitem__``, slicing the 13 | array automatically updates the dimension and origin information. Images are 14 | manipulated in C++ as 4D images (IRTK behaviour), but flat dimensions are 15 | removed from Python thanks to an automated call to ``numpy.squeeze``. 16 | 17 | Indices are ordered TZYX, eg ``img[t,z,y,x]``, which corresponds to the raw 18 | pixel array of IRTK but differs from the ``img(x,y,z,t)`` C++ 19 | interface. Nonetheless, the order in the information header still correspond to 20 | the C++ order, that is to say ``img.header['dim'][0]`` corresponds to 21 | ``img.GetX()`` and is equal to ``img.shape[-1]``, ``img.header['pixelSize'][0]`` corresponds to 22 | ``img.GetXSize()``, ``img.header['orientation'][0]`` corresponds to ``xaxis``, 23 | and finally ``img.header['origin'][0]`` correspond to the X origin. 24 | 25 | 26 | Below is a basic example: 27 | 28 | .. code-block:: python 29 | 30 | # load the module 31 | import irtk 32 | 33 | # read an image 34 | img = irtk.imread("5066_4.nii", dtype="float32") 35 | print img.min(), img.max(), img.std() # methods inherited from numpy.ndarray 36 | 37 | # write a PNG thumbnail after saturation, displaying a segmentation by thresholding 38 | irtk.imshow(img.saturate(0.01,0.99), img > 2000, opacity=0.4, filename="thumbnail.png") 39 | 40 | 41 | .. image:: images/thumbnail.png 42 | :align: center 43 | :height: 200pt 44 | 45 | 46 | Below is a more complex example where we read several scans, register them all 47 | to the first one and compute an average volume: 48 | 49 | .. code-block:: python 50 | 51 | import sys 52 | import irtk 53 | 54 | filenames = sys.argv[1:] 55 | 56 | img1 = irtk.imread(filenames[0], dtype='float32') 57 | img1 = img1.rescale() 58 | weights = (img1 > 0).astype('int') 59 | 60 | for f in filenames[1:]: 61 | img2 = irtk.imread( f, dtype='float32').rescale() 62 | t = img2.register(img1) # rigid registration 63 | img2 = img2.transform(t,target=img1) # linear interpolation by default 64 | img1 += img2 65 | weights += img2 > 0 66 | 67 | img1 /= weights.astype('float32') + 0.000001 # avoid division by zero 68 | 69 | # write image to disk 70 | irtk.imwrite( "average.nii", img1) 71 | 72 | # save thumbnail 73 | irtk.imshow( img1, filename="average.png" ) 74 | 75 | 76 | .. image:: images/average.png 77 | :align: center 78 | :height: 200pt 79 | 80 | .. toctree:: 81 | :maxdepth: 2 82 | 83 | why.rst 84 | 85 | Module reference 86 | ================ 87 | 88 | .. toctree:: 89 | :maxdepth: 2 90 | 91 | .. automodule:: irtk 92 | :special-members: __new__ 93 | :members: 94 | 95 | Indices and tables 96 | ================== 97 | 98 | * :ref:`genindex` 99 | * :ref:`modindex` 100 | * :ref:`search` 101 | 102 | -------------------------------------------------------------------------------- /doc/source/sphinxext/LICENSE.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | The files 3 | - numpydoc.py 4 | - autosummary.py 5 | - autosummary_generate.py 6 | - docscrape.py 7 | - docscrape_sphinx.py 8 | - phantom_import.py 9 | have the following license: 10 | 11 | Copyright (C) 2008 Stefan van der Walt , Pauli Virtanen 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are 15 | met: 16 | 17 | 1. Redistributions of source code must retain the above copyright 18 | notice, this list of conditions and the following disclaimer. 19 | 2. Redistributions in binary form must reproduce the above copyright 20 | notice, this list of conditions and the following disclaimer in 21 | the documentation and/or other materials provided with the 22 | distribution. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 28 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 | POSSIBILITY OF SUCH DAMAGE. 35 | 36 | -------------------------------------------------------------------------------- /doc/source/sphinxext/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioMedIA/python-irtk/0ca6f94dcbe27807ce3e0c408354c47354e974bc/doc/source/sphinxext/__init__.py -------------------------------------------------------------------------------- /doc/source/sphinxext/autosummary.py: -------------------------------------------------------------------------------- 1 | """ 2 | =========== 3 | autosummary 4 | =========== 5 | 6 | Sphinx extension that adds an autosummary:: directive, which can be 7 | used to generate function/method/attribute/etc. summary lists, similar 8 | to those output eg. by Epydoc and other API doc generation tools. 9 | 10 | An :autolink: role is also provided. 11 | 12 | autosummary directive 13 | --------------------- 14 | 15 | The autosummary directive has the form:: 16 | 17 | .. autosummary:: 18 | :nosignatures: 19 | :toctree: generated/ 20 | 21 | module.function_1 22 | module.function_2 23 | ... 24 | 25 | and it generates an output table (containing signatures, optionally) 26 | 27 | ======================== ============================================= 28 | module.function_1(args) Summary line from the docstring of function_1 29 | module.function_2(args) Summary line from the docstring 30 | ... 31 | ======================== ============================================= 32 | 33 | If the :toctree: option is specified, files matching the function names 34 | are inserted to the toctree with the given prefix: 35 | 36 | generated/module.function_1 37 | generated/module.function_2 38 | ... 39 | 40 | Note: The file names contain the module:: or currentmodule:: prefixes. 41 | 42 | .. seealso:: autosummary_generate.py 43 | 44 | 45 | autolink role 46 | ------------- 47 | 48 | The autolink role functions as ``:obj:`` when the name referred can be 49 | resolved to a Python object, and otherwise it becomes simple emphasis. 50 | This can be used as the default role to make links 'smart'. 51 | 52 | """ 53 | import sys 54 | import posixpath 55 | import re 56 | 57 | try: 58 | from docutils import nodes 59 | except ImportError: 60 | # This won't work, but we have to have the module importable, 61 | # so that nose can do its discovery scan, so we stub docutils 62 | class nodes(object): 63 | comment = object 64 | 65 | if sys.version_info[0] == 2: 66 | from docscrape_sphinx import get_doc_object 67 | else: 68 | from .docscrape_sphinx import get_doc_object 69 | 70 | 71 | def setup(app): 72 | from docutils.parsers.rst import directives 73 | app.add_directive('autosummary', 74 | autosummary_directive, True, (0, 0, False), 75 | toctree=directives.unchanged, 76 | nosignatures=directives.flag) 77 | app.add_role('autolink', autolink_role) 78 | 79 | app.add_node(autosummary_toc, 80 | html=(autosummary_toc_visit_html, 81 | autosummary_toc_depart_noop), 82 | latex=(autosummary_toc_visit_latex, 83 | autosummary_toc_depart_noop)) 84 | 85 | app.connect('doctree-read', process_autosummary_toc) 86 | 87 | 88 | #------------------------------------------------------------------------------ 89 | # autosummary_toc node 90 | #------------------------------------------------------------------------------ 91 | 92 | 93 | class autosummary_toc(nodes.comment): 94 | pass 95 | 96 | 97 | def process_autosummary_toc(app, doctree): 98 | """ 99 | Insert items described in autosummary:: to the TOC tree, but do 100 | not generate the toctree:: list. 101 | 102 | """ 103 | import sphinx.addnodes 104 | env = app.builder.env 105 | crawled = {} 106 | 107 | def crawl_toc(node, depth=1): 108 | crawled[node] = True 109 | for j, subnode in enumerate(node): 110 | try: 111 | if (isinstance(subnode, autosummary_toc) 112 | and isinstance(subnode[0], sphinx.addnodes.toctree)): 113 | env.note_toctree(env.docname, subnode[0]) 114 | continue 115 | except IndexError: 116 | continue 117 | if not isinstance(subnode, nodes.section): 118 | continue 119 | if subnode not in crawled: 120 | crawl_toc(subnode, depth + 1) 121 | crawl_toc(doctree) 122 | 123 | 124 | def autosummary_toc_visit_html(self, node): 125 | """Hide autosummary toctree list in HTML output""" 126 | raise nodes.SkipNode 127 | 128 | 129 | def autosummary_toc_visit_latex(self, node): 130 | """Show autosummary toctree (= put the referenced pages here) in Latex""" 131 | pass 132 | 133 | 134 | def autosummary_toc_depart_noop(self, node): 135 | pass 136 | 137 | 138 | #------------------------------------------------------------------------------ 139 | # .. autosummary:: 140 | #------------------------------------------------------------------------------ 141 | 142 | 143 | def autosummary_directive(dirname, arguments, options, content, lineno, 144 | content_offset, block_text, state, state_machine): 145 | """ 146 | Pretty table containing short signatures and summaries of functions etc. 147 | 148 | autosummary also generates a (hidden) toctree:: node. 149 | 150 | """ 151 | import sphinx.addnodes 152 | 153 | names = [] 154 | names += [x.strip() for x in content if x.strip()] 155 | 156 | table, warnings, real_names = get_autosummary(names, state, 157 | 'nosignatures' in options) 158 | node = table 159 | 160 | env = state.document.settings.env 161 | suffix = env.config.source_suffix 162 | all_docnames = env.found_docs.copy() 163 | dirname = posixpath.dirname(env.docname) 164 | 165 | if 'toctree' in options: 166 | tree_prefix = options['toctree'].strip() 167 | docnames = [] 168 | for name in names: 169 | name = real_names.get(name, name) 170 | 171 | docname = tree_prefix + name 172 | if docname.endswith(suffix): 173 | docname = docname[:-len(suffix)] 174 | docname = posixpath.normpath(posixpath.join(dirname, docname)) 175 | if docname not in env.found_docs: 176 | warnings.append(state.document.reporter.warning( 177 | 'toctree references unknown document %r' % docname, 178 | line=lineno)) 179 | docnames.append(docname) 180 | 181 | tocnode = sphinx.addnodes.toctree() 182 | tocnode['includefiles'] = docnames 183 | tocnode['maxdepth'] = -1 184 | tocnode['glob'] = None 185 | tocnode['entries'] = [] 186 | 187 | tocnode = autosummary_toc('', '', tocnode) 188 | return warnings + [node] + [tocnode] 189 | else: 190 | return warnings + [node] 191 | 192 | 193 | def get_autosummary(names, state, no_signatures=False): 194 | """ 195 | Generate a proper table node for autosummary:: directive. 196 | 197 | Parameters 198 | ---------- 199 | names : list of str 200 | Names of Python objects to be imported and added to the table. 201 | document : document 202 | Docutils document object 203 | 204 | """ 205 | 206 | from docutils.statemachine import ViewList 207 | document = state.document 208 | 209 | real_names = {} 210 | warnings = [] 211 | 212 | prefixes = [''] 213 | prefixes.insert(0, document.settings.env.currmodule) 214 | 215 | table = nodes.table('') 216 | group = nodes.tgroup('', cols=2) 217 | table.append(group) 218 | group.append(nodes.colspec('', colwidth=30)) 219 | group.append(nodes.colspec('', colwidth=70)) 220 | body = nodes.tbody('') 221 | group.append(body) 222 | 223 | def append_row(*column_texts): 224 | row = nodes.row('') 225 | for text in column_texts: 226 | node = nodes.paragraph('') 227 | vl = ViewList() 228 | vl.append(text, '') 229 | state.nested_parse(vl, 0, node) 230 | row.append(nodes.entry('', node)) 231 | body.append(row) 232 | 233 | for name in names: 234 | try: 235 | obj, real_name = import_by_name(name, prefixes=prefixes) 236 | except ImportError: 237 | warnings.append(document.reporter.warning( 238 | 'failed to import %s' % name)) 239 | append_row(":obj:`%s`" % name, "") 240 | continue 241 | 242 | real_names[name] = real_name 243 | 244 | doc = get_doc_object(obj) 245 | 246 | if doc['Summary']: 247 | title = " ".join(doc['Summary']) 248 | else: 249 | title = "" 250 | 251 | col1 = ":obj:`%s <%s>`" % (name, real_name) 252 | if doc['Signature']: 253 | sig = re.sub('^[a-zA-Z_0-9.-]*', '', doc['Signature']) 254 | if '=' in sig: 255 | # abbreviate optional arguments 256 | sig = re.sub(r', ([a-zA-Z0-9_]+)=', r'[, \1=', sig, count=1) 257 | sig = re.sub(r'\(([a-zA-Z0-9_]+)=', r'([\1=', sig, count=1) 258 | sig = re.sub(r'=[^,)]+,', ',', sig) 259 | sig = re.sub(r'=[^,)]+\)$', '])', sig) 260 | # shorten long strings 261 | sig = re.sub(r'(\[.{16,16}[^,)]*?),.*?\]\)', r'\1, ...])', sig) 262 | else: 263 | sig = re.sub(r'(\(.{16,16}[^,)]*?),.*?\)', r'\1, ...)', sig) 264 | col1 += " " + sig 265 | col2 = title 266 | append_row(col1, col2) 267 | 268 | return table, warnings, real_names 269 | 270 | 271 | def import_by_name(name, prefixes=[None]): 272 | """ 273 | Import a Python object that has the given name, under one of the prefixes. 274 | 275 | Parameters 276 | ---------- 277 | name : str 278 | Name of a Python object, eg. 'numpy.ndarray.view' 279 | prefixes : list of (str or None), optional 280 | Prefixes to prepend to the name (None implies no prefix). 281 | The first prefixed name that results to successful import is used. 282 | 283 | Returns 284 | ------- 285 | obj 286 | The imported object 287 | name 288 | Name of the imported object (useful if `prefixes` was used) 289 | 290 | """ 291 | 292 | for prefix in prefixes: 293 | try: 294 | if prefix: 295 | prefixed_name = '.'.join([prefix, name]) 296 | else: 297 | prefixed_name = name 298 | return _import_by_name(prefixed_name), prefixed_name 299 | except ImportError: 300 | pass 301 | raise ImportError 302 | 303 | 304 | def _import_by_name(name): 305 | """Import a Python object given its full name""" 306 | try: 307 | # try first interpret `name` as MODNAME.OBJ 308 | name_parts = name.split('.') 309 | try: 310 | modname = '.'.join(name_parts[:-1]) 311 | __import__(modname) 312 | return getattr(sys.modules[modname], name_parts[-1]) 313 | except (ImportError, IndexError, AttributeError): 314 | pass 315 | 316 | # ... then as MODNAME, MODNAME.OBJ1, MODNAME.OBJ1.OBJ2, ... 317 | last_j = 0 318 | modname = None 319 | for j in reversed(range(1, len(name_parts) + 1)): 320 | last_j = j 321 | modname = '.'.join(name_parts[:j]) 322 | try: 323 | __import__(modname) 324 | except ImportError: 325 | continue 326 | if modname in sys.modules: 327 | break 328 | 329 | if last_j < len(name_parts): 330 | obj = sys.modules[modname] 331 | for obj_name in name_parts[last_j:]: 332 | obj = getattr(obj, obj_name) 333 | return obj 334 | else: 335 | return sys.modules[modname] 336 | except (ValueError, ImportError, AttributeError, KeyError) as e: 337 | raise ImportError(e) 338 | 339 | #------------------------------------------------------------------------------ 340 | # :autolink: (smart default role) 341 | #------------------------------------------------------------------------------ 342 | 343 | 344 | def autolink_role(typ, rawtext, etext, lineno, inliner, 345 | options={}, content=[]): 346 | """ 347 | Smart linking role. 348 | 349 | Expands to ":obj:`text`" if `text` is an object that can be imported; 350 | otherwise expands to "*text*". 351 | """ 352 | import sphinx.roles 353 | r = sphinx.roles.xfileref_role('obj', rawtext, etext, lineno, inliner, 354 | options, content) 355 | pnode = r[0][0] 356 | 357 | prefixes = [None] 358 | #prefixes.insert(0, inliner.document.settings.env.currmodule) 359 | try: 360 | obj, name = import_by_name(pnode['reftarget'], prefixes) 361 | except ImportError: 362 | content = pnode[0] 363 | r[0][0] = nodes.emphasis(rawtext, content[0].astext(), 364 | classes=content['classes']) 365 | return r 366 | -------------------------------------------------------------------------------- /doc/source/sphinxext/autosummary_generate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | r""" 3 | autosummary_generate.py OPTIONS FILES 4 | 5 | Generate automatic RST source files for items referred to in 6 | autosummary:: directives. 7 | 8 | Each generated RST file contains a single auto*:: directive which 9 | extracts the docstring of the referred item. 10 | 11 | Example Makefile rule:: 12 | 13 | generate: 14 | ./ext/autosummary_generate.py -o source/generated source/*.rst 15 | 16 | """ 17 | import re 18 | import inspect 19 | import os 20 | import optparse 21 | import pydoc 22 | import sys 23 | 24 | if sys.version_info[0] == 2: 25 | from autosummary import import_by_name 26 | else: 27 | from .autosummary import import_by_name 28 | 29 | 30 | try: 31 | from phantom_import import import_phantom_module 32 | except ImportError: 33 | import_phantom_module = lambda x: x 34 | 35 | 36 | def main(): 37 | p = optparse.OptionParser(__doc__.strip()) 38 | p.add_option("-p", "--phantom", action="store", type="string", 39 | dest="phantom", default=None, 40 | help="Phantom import modules from a file") 41 | p.add_option("-o", "--output-dir", action="store", type="string", 42 | dest="output_dir", default=None, 43 | help=("Write all output files to the given " 44 | "directory (instead of writing them as specified " 45 | "in the autosummary::directives)")) 46 | options, args = p.parse_args() 47 | 48 | if len(args) == 0: 49 | p.error("wrong number of arguments") 50 | 51 | if options.phantom and os.path.isfile(options.phantom): 52 | import_phantom_module(options.phantom) 53 | 54 | # read 55 | names = {} 56 | for name, loc in get_documented(args).items(): 57 | for (filename, sec_title, keyword, toctree) in loc: 58 | if toctree is not None: 59 | path = os.path.join(os.path.dirname(filename), toctree) 60 | names[name] = os.path.abspath(path) 61 | 62 | # write 63 | for name, path in sorted(names.items()): 64 | if options.output_dir is not None: 65 | path = options.output_dir 66 | 67 | if not os.path.isdir(path): 68 | os.makedirs(path) 69 | 70 | try: 71 | obj, name = import_by_name(name) 72 | except ImportError, e: 73 | print "Failed to import '%s': %s" % (name, e) 74 | continue 75 | 76 | fn = os.path.join(path, '%s.rst' % name) 77 | 78 | if os.path.exists(fn): 79 | # skip 80 | continue 81 | 82 | f = open(fn, 'w') 83 | 84 | try: 85 | f.write('%s\n%s\n\n' % (name, '=' * len(name))) 86 | 87 | if inspect.isclass(obj): 88 | if issubclass(obj, Exception): 89 | f.write(format_modulemember(name, 'autoexception')) 90 | else: 91 | f.write(format_modulemember(name, 'autoclass')) 92 | elif inspect.ismodule(obj): 93 | f.write(format_modulemember(name, 'automodule')) 94 | elif inspect.ismethod(obj) or inspect.ismethoddescriptor(obj): 95 | f.write(format_classmember(name, 'automethod')) 96 | elif callable(obj): 97 | f.write(format_modulemember(name, 'autofunction')) 98 | elif hasattr(obj, '__get__'): 99 | f.write(format_classmember(name, 'autoattribute')) 100 | else: 101 | f.write(format_modulemember(name, 'autofunction')) 102 | finally: 103 | f.close() 104 | 105 | 106 | def format_modulemember(name, directive): 107 | parts = name.split('.') 108 | mod, name = '.'.join(parts[:-1]), parts[-1] 109 | return ".. currentmodule:: %s\n\n.. %s:: %s\n" % (mod, directive, name) 110 | 111 | 112 | def format_classmember(name, directive): 113 | parts = name.split('.') 114 | mod, name = '.'.join(parts[:-2]), '.'.join(parts[-2:]) 115 | return ".. currentmodule:: %s\n\n.. %s:: %s\n" % (mod, directive, name) 116 | 117 | 118 | def get_documented(filenames): 119 | """ 120 | Find out what items are documented in source/*.rst 121 | See `get_documented_in_lines`. 122 | 123 | """ 124 | documented = {} 125 | for filename in filenames: 126 | f = open(filename, 'r') 127 | lines = f.read().splitlines() 128 | documented.update(get_documented_in_lines(lines, filename=filename)) 129 | f.close() 130 | return documented 131 | 132 | 133 | def get_documented_in_docstring(name, module=None, filename=None): 134 | """ 135 | Find out what items are documented in the given object's docstring. 136 | See `get_documented_in_lines`. 137 | 138 | """ 139 | try: 140 | obj, real_name = import_by_name(name) 141 | lines = pydoc.getdoc(obj).splitlines() 142 | return get_documented_in_lines(lines, module=name, filename=filename) 143 | except AttributeError: 144 | pass 145 | except ImportError, e: 146 | print "Failed to import '%s': %s" % (name, e) 147 | return {} 148 | 149 | 150 | def get_documented_in_lines(lines, module=None, filename=None): 151 | """ 152 | Find out what items are documented in the given lines 153 | 154 | Returns 155 | ------- 156 | documented : dict of list of (filename, title, keyword, toctree) 157 | Dictionary whose keys are documented names of objects. 158 | The value is a list of locations where the object was documented. 159 | Each location is a tuple of filename, the current section title, 160 | the name of the directive, and the value of the :toctree: argument 161 | (if present) of the directive. 162 | 163 | """ 164 | title_underline_re = re.compile("^[-=*_^#]{3,}\s*$") 165 | autodoc_re = re.compile(".. auto(function|method|attribute|class \ 166 | |exception|module)::\s*([A-Za-z0-9_.]+)\s*$") 167 | autosummary_re = re.compile(r'^\.\.\s+autosummary::\s*') 168 | module_re = re.compile( 169 | r'^\.\.\s+(current)?module::\s*([a-zA-Z0-9_.]+)\s*$') 170 | autosummary_item_re = re.compile(r'^\s+([_a-zA-Z][a-zA-Z0-9_.]*)\s*') 171 | toctree_arg_re = re.compile(r'^\s+:toctree:\s*(.*?)\s*$') 172 | 173 | documented = {} 174 | 175 | current_title = [] 176 | last_line = None 177 | toctree = None 178 | current_module = module 179 | in_autosummary = False 180 | 181 | for line in lines: 182 | try: 183 | if in_autosummary: 184 | m = toctree_arg_re.match(line) 185 | if m: 186 | toctree = m.group(1) 187 | continue 188 | 189 | if line.strip().startswith(':'): 190 | continue # skip options 191 | 192 | m = autosummary_item_re.match(line) 193 | if m: 194 | name = m.group(1).strip() 195 | if current_module and not name.startswith( 196 | current_module + '.'): 197 | name = "%s.%s" % (current_module, name) 198 | 199 | documented.setdefault(name, []).append( 200 | (filename, current_title, 'autosummary', toctree)) 201 | continue 202 | if line.strip() == '': 203 | continue 204 | in_autosummary = False 205 | 206 | m = autosummary_re.match(line) 207 | if m: 208 | in_autosummary = True 209 | continue 210 | 211 | m = autodoc_re.search(line) 212 | if m: 213 | name = m.group(2).strip() 214 | if m.group(1) == "module": 215 | current_module = name 216 | documented.update(get_documented_in_docstring( 217 | name, filename=filename)) 218 | elif current_module and not name.startswith( 219 | current_module + '.'): 220 | name = "%s.%s" % (current_module, name) 221 | 222 | documented.setdefault(name, []).append( 223 | (filename, current_title, "auto" + m.group(1), None)) 224 | continue 225 | 226 | m = title_underline_re.match(line) 227 | if m and last_line: 228 | current_title = last_line.strip() 229 | continue 230 | 231 | m = module_re.match(line) 232 | if m: 233 | current_module = m.group(2) 234 | continue 235 | finally: 236 | last_line = line 237 | 238 | return documented 239 | 240 | if __name__ == "__main__": 241 | main() 242 | -------------------------------------------------------------------------------- /doc/source/sphinxext/docscrape.py: -------------------------------------------------------------------------------- 1 | """Extract reference documentation from the NumPy source tree. 2 | 3 | """ 4 | 5 | import inspect 6 | import textwrap 7 | import re 8 | import pydoc 9 | from warnings import warn 10 | 11 | 12 | class Reader(object): 13 | """A line-based string reader. 14 | 15 | """ 16 | def __init__(self, data): 17 | """ 18 | Parameters 19 | ---------- 20 | data : str 21 | String with lines separated by '\n'. 22 | 23 | """ 24 | if isinstance(data, list): 25 | self._str = data 26 | else: 27 | self._str = data.split('\n') # store string as list of lines 28 | 29 | self.reset() 30 | 31 | def __getitem__(self, n): 32 | return self._str[n] 33 | 34 | def reset(self): 35 | self._l = 0 # current line nr 36 | 37 | def read(self): 38 | if not self.eof(): 39 | out = self[self._l] 40 | self._l += 1 41 | return out 42 | else: 43 | return '' 44 | 45 | def seek_next_non_empty_line(self): 46 | for l in self[self._l:]: 47 | if l.strip(): 48 | break 49 | else: 50 | self._l += 1 51 | 52 | def eof(self): 53 | return self._l >= len(self._str) 54 | 55 | def read_to_condition(self, condition_func): 56 | start = self._l 57 | for line in self[start:]: 58 | if condition_func(line): 59 | return self[start:self._l] 60 | self._l += 1 61 | if self.eof(): 62 | return self[start:self._l + 1] 63 | return [] 64 | 65 | def read_to_next_empty_line(self): 66 | self.seek_next_non_empty_line() 67 | 68 | def is_empty(line): 69 | return not line.strip() 70 | return self.read_to_condition(is_empty) 71 | 72 | def read_to_next_unindented_line(self): 73 | def is_unindented(line): 74 | return (line.strip() and (len(line.lstrip()) == len(line))) 75 | return self.read_to_condition(is_unindented) 76 | 77 | def peek(self, n=0): 78 | if self._l + n < len(self._str): 79 | return self[self._l + n] 80 | else: 81 | return '' 82 | 83 | def is_empty(self): 84 | return not ''.join(self._str).strip() 85 | 86 | 87 | class NumpyDocString(object): 88 | def __init__(self, docstring): 89 | docstring = textwrap.dedent(docstring).split('\n') 90 | 91 | self._doc = Reader(docstring) 92 | self._parsed_data = { 93 | 'Signature': '', 94 | 'Summary': [''], 95 | 'Extended Summary': [], 96 | 'Parameters': [], 97 | 'Returns': [], 98 | 'Raises': [], 99 | 'Warns': [], 100 | 'Other Parameters': [], 101 | 'Attributes': [], 102 | 'Methods': [], 103 | 'See Also': [], 104 | 'Notes': [], 105 | 'Warnings': [], 106 | 'References': '', 107 | 'Examples': '', 108 | 'index': {} 109 | } 110 | 111 | self._parse() 112 | 113 | def __getitem__(self, key): 114 | return self._parsed_data[key] 115 | 116 | def __setitem__(self, key, val): 117 | if not self._parsed_data.has_key(key): 118 | warn("Unknown section %s" % key) 119 | else: 120 | self._parsed_data[key] = val 121 | 122 | def _is_at_section(self): 123 | self._doc.seek_next_non_empty_line() 124 | 125 | if self._doc.eof(): 126 | return False 127 | 128 | l1 = self._doc.peek().strip() # e.g. Parameters 129 | 130 | if l1.startswith('.. index::'): 131 | return True 132 | 133 | l2 = self._doc.peek(1).strip() # ---------- or ========== 134 | return l2.startswith('-' * len(l1)) or l2.startswith('=' * len(l1)) 135 | 136 | def _strip(self, doc): 137 | i = 0 138 | j = 0 139 | for i, line in enumerate(doc): 140 | if line.strip(): 141 | break 142 | 143 | for j, line in enumerate(doc[::-1]): 144 | if line.strip(): 145 | break 146 | 147 | return doc[i:len(doc) - j] 148 | 149 | def _read_to_next_section(self): 150 | section = self._doc.read_to_next_empty_line() 151 | 152 | while not self._is_at_section() and not self._doc.eof(): 153 | if not self._doc.peek(-1).strip(): # previous line was empty 154 | section += [''] 155 | 156 | section += self._doc.read_to_next_empty_line() 157 | 158 | return section 159 | 160 | def _read_sections(self): 161 | while not self._doc.eof(): 162 | data = self._read_to_next_section() 163 | name = data[0].strip() 164 | 165 | if name.startswith('..'): # index section 166 | yield name, data[1:] 167 | elif len(data) < 2: 168 | yield StopIteration 169 | else: 170 | yield name, self._strip(data[2:]) 171 | 172 | def _parse_param_list(self, content): 173 | r = Reader(content) 174 | params = [] 175 | while not r.eof(): 176 | header = r.read().strip() 177 | if ' : ' in header: 178 | arg_name, arg_type = header.split(' : ')[:2] 179 | else: 180 | arg_name, arg_type = header, '' 181 | 182 | desc = r.read_to_next_unindented_line() 183 | desc = dedent_lines(desc) 184 | 185 | params.append((arg_name, arg_type, desc)) 186 | 187 | return params 188 | 189 | _name_rgx = re.compile(r"^\s*(:(?P\w+):`(?P[a-zA-Z0-9_.-]+)`|" 190 | r" (?P[a-zA-Z0-9_.-]+))\s*", re.X) 191 | 192 | def _parse_see_also(self, content): 193 | """ 194 | func_name : Descriptive text 195 | continued text 196 | another_func_name : Descriptive text 197 | func_name1, func_name2, :meth:`func_name`, func_name3 198 | 199 | """ 200 | items = [] 201 | 202 | def parse_item_name(text): 203 | """Match ':role:`name`' or 'name'""" 204 | m = self._name_rgx.match(text) 205 | if m: 206 | g = m.groups() 207 | if g[1] is None: 208 | return g[3], None 209 | else: 210 | return g[2], g[1] 211 | raise ValueError("%s is not a item name" % text) 212 | 213 | def push_item(name, rest): 214 | if not name: 215 | return 216 | name, role = parse_item_name(name) 217 | items.append((name, list(rest), role)) 218 | del rest[:] 219 | 220 | current_func = None 221 | rest = [] 222 | 223 | for line in content: 224 | if not line.strip(): 225 | continue 226 | 227 | m = self._name_rgx.match(line) 228 | if m and line[m.end():].strip().startswith(':'): 229 | push_item(current_func, rest) 230 | current_func, line = line[:m.end()], line[m.end():] 231 | rest = [line.split(':', 1)[1].strip()] 232 | if not rest[0]: 233 | rest = [] 234 | elif not line.startswith(' '): 235 | push_item(current_func, rest) 236 | current_func = None 237 | if ',' in line: 238 | for func in line.split(','): 239 | push_item(func, []) 240 | elif line.strip(): 241 | current_func = line 242 | elif current_func is not None: 243 | rest.append(line.strip()) 244 | push_item(current_func, rest) 245 | return items 246 | 247 | def _parse_index(self, section, content): 248 | """ 249 | .. index: default 250 | :refguide: something, else, and more 251 | 252 | """ 253 | def strip_each_in(lst): 254 | return [s.strip() for s in lst] 255 | 256 | out = {} 257 | section = section.split('::') 258 | if len(section) > 1: 259 | out['default'] = strip_each_in(section[1].split(','))[0] 260 | for line in content: 261 | line = line.split(':') 262 | if len(line) > 2: 263 | out[line[1]] = strip_each_in(line[2].split(',')) 264 | return out 265 | 266 | def _parse_summary(self): 267 | """Grab signature (if given) and summary""" 268 | if self._is_at_section(): 269 | return 270 | 271 | summary = self._doc.read_to_next_empty_line() 272 | summary_str = " ".join([s.strip() for s in summary]).strip() 273 | if re.compile('^([\w., ]+=)?\s*[\w\.]+\(.*\)$').match(summary_str): 274 | self['Signature'] = summary_str 275 | if not self._is_at_section(): 276 | self['Summary'] = self._doc.read_to_next_empty_line() 277 | else: 278 | self['Summary'] = summary 279 | 280 | if not self._is_at_section(): 281 | self['Extended Summary'] = self._read_to_next_section() 282 | 283 | def _parse(self): 284 | self._doc.reset() 285 | self._parse_summary() 286 | 287 | for (section, content) in self._read_sections(): 288 | if not section.startswith('..'): 289 | section = ' '.join([s.capitalize() for s in section.split(' ') 290 | ]) 291 | if section in ('Parameters', 'Attributes', 'Methods', 292 | 'Returns', 'Raises', 'Warns'): 293 | self[section] = self._parse_param_list(content) 294 | elif section.startswith('.. index::'): 295 | self['index'] = self._parse_index(section, content) 296 | elif section == 'See Also': 297 | self['See Also'] = self._parse_see_also(content) 298 | else: 299 | self[section] = content 300 | 301 | # string conversion routines 302 | 303 | def _str_header(self, name, symbol='-'): 304 | return [name, len(name) * symbol] 305 | 306 | def _str_indent(self, doc, indent=4): 307 | out = [] 308 | for line in doc: 309 | out += [' ' * indent + line] 310 | return out 311 | 312 | def _str_signature(self): 313 | if self['Signature']: 314 | return [self['Signature'].replace('*', '\*')] + [''] 315 | else: 316 | return [''] 317 | 318 | def _str_summary(self): 319 | if self['Summary']: 320 | return self['Summary'] + [''] 321 | else: 322 | return [] 323 | 324 | def _str_extended_summary(self): 325 | if self['Extended Summary']: 326 | return self['Extended Summary'] + [''] 327 | else: 328 | return [] 329 | 330 | def _str_param_list(self, name): 331 | out = [] 332 | if self[name]: 333 | out += self._str_header(name) 334 | for param, param_type, desc in self[name]: 335 | out += ['%s : %s' % (param, param_type)] 336 | out += self._str_indent(desc) 337 | out += [''] 338 | return out 339 | 340 | def _str_section(self, name): 341 | out = [] 342 | if self[name]: 343 | out += self._str_header(name) 344 | out += self[name] 345 | out += [''] 346 | return out 347 | 348 | def _str_see_also(self, func_role): 349 | if not self['See Also']: 350 | return [] 351 | out = [] 352 | out += self._str_header("See Also") 353 | last_had_desc = True 354 | for func, desc, role in self['See Also']: 355 | if role: 356 | link = ':%s:`%s`' % (role, func) 357 | elif func_role: 358 | link = ':%s:`%s`' % (func_role, func) 359 | else: 360 | link = "`%s`_" % func 361 | if desc or last_had_desc: 362 | out += [''] 363 | out += [link] 364 | else: 365 | out[-1] += ", %s" % link 366 | if desc: 367 | out += self._str_indent([' '.join(desc)]) 368 | last_had_desc = True 369 | else: 370 | last_had_desc = False 371 | out += [''] 372 | return out 373 | 374 | def _str_index(self): 375 | idx = self['index'] 376 | out = [] 377 | out += ['.. index:: %s' % idx.get('default', '')] 378 | for section, references in idx.iteritems(): 379 | if section == 'default': 380 | continue 381 | out += [' :%s: %s' % (section, ', '.join(references))] 382 | return out 383 | 384 | def __str__(self, func_role=''): 385 | out = [] 386 | out += self._str_signature() 387 | out += self._str_summary() 388 | out += self._str_extended_summary() 389 | for param_list in ('Parameters', 'Returns', 'Raises'): 390 | out += self._str_param_list(param_list) 391 | out += self._str_section('Warnings') 392 | out += self._str_see_also(func_role) 393 | for s in ('Notes', 'References', 'Examples'): 394 | out += self._str_section(s) 395 | out += self._str_index() 396 | return '\n'.join(out) 397 | 398 | 399 | def indent(str, indent=4): 400 | indent_str = ' ' * indent 401 | if str is None: 402 | return indent_str 403 | lines = str.split('\n') 404 | return '\n'.join(indent_str + l for l in lines) 405 | 406 | 407 | def dedent_lines(lines): 408 | """Deindent a list of lines maximally""" 409 | return textwrap.dedent("\n".join(lines)).split("\n") 410 | 411 | 412 | def header(text, style='-'): 413 | return text + '\n' + style * len(text) + '\n' 414 | 415 | 416 | class FunctionDoc(NumpyDocString): 417 | def __init__(self, func, role='func'): 418 | self._f = func 419 | self._role = role # e.g. "func" or "meth" 420 | try: 421 | NumpyDocString.__init__(self, inspect.getdoc(func) or '') 422 | except ValueError as e: 423 | print('*' * 78) 424 | print("ERROR: '%s' while parsing `%s`" % (e, self._f)) 425 | print('*' * 78) 426 | 427 | if not self['Signature']: 428 | func, func_name = self.get_func() 429 | try: 430 | # try to read signature 431 | argspec = inspect.getargspec(func) 432 | argspec = inspect.formatargspec(*argspec) 433 | argspec = argspec.replace('*', '\*') 434 | signature = '%s%s' % (func_name, argspec) 435 | except TypeError as e: 436 | signature = '%s()' % func_name 437 | self['Signature'] = signature 438 | 439 | def get_func(self): 440 | func_name = getattr(self._f, '__name__', self.__class__.__name__) 441 | if inspect.isclass(self._f): 442 | func = getattr(self._f, '__call__', self._f.__init__) 443 | else: 444 | func = self._f 445 | return func, func_name 446 | 447 | def __str__(self): 448 | out = '' 449 | 450 | func, func_name = self.get_func() 451 | signature = self['Signature'].replace('*', '\*') 452 | 453 | roles = {'func': 'function', 454 | 'meth': 'method'} 455 | 456 | if self._role: 457 | if not roles.has_key(self._role): 458 | print("Warning: invalid role %s" % self._role) 459 | out += '.. %s:: %s\n \n\n' % (roles.get(self._role, ''), 460 | func_name) 461 | 462 | out += super(FunctionDoc, self).__str__(func_role=self._role) 463 | return out 464 | 465 | 466 | class ClassDoc(NumpyDocString): 467 | def __init__(self, cls, modulename='', func_doc=FunctionDoc): 468 | if not inspect.isclass(cls): 469 | raise ValueError("Initialise using a class. Got %r" % cls) 470 | self._cls = cls 471 | 472 | if modulename and not modulename.endswith('.'): 473 | modulename += '.' 474 | self._mod = modulename 475 | self._name = cls.__name__ 476 | self._func_doc = func_doc 477 | 478 | NumpyDocString.__init__(self, pydoc.getdoc(cls)) 479 | 480 | @property 481 | def methods(self): 482 | return [name for name, func in inspect.getmembers(self._cls) 483 | if not name.startswith('_') and callable(func)] 484 | 485 | def __str__(self): 486 | out = '' 487 | out += super(ClassDoc, self).__str__() 488 | out += "\n\n" 489 | 490 | #for m in self.methods: 491 | # print "Parsing `%s`" % m 492 | # out += str(self._func_doc(getattr(self._cls,m), 'meth')) + '\n\n' 493 | # out += '.. index::\n single: %s; %s\n\n' % (self._name, m) 494 | 495 | return out 496 | -------------------------------------------------------------------------------- /doc/source/sphinxext/docscrape_sphinx.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import textwrap 3 | import pydoc 4 | import sys 5 | 6 | if sys.version_info[0] == 2: 7 | from docscrape import NumpyDocString 8 | from docscrape import FunctionDoc 9 | from docscrape import ClassDoc 10 | else: 11 | from .docscrape import NumpyDocString 12 | from .docscrape import FunctionDoc 13 | from .docscrape import ClassDoc 14 | 15 | 16 | class SphinxDocString(NumpyDocString): 17 | # string conversion routines 18 | def _str_header(self, name, symbol='`'): 19 | return ['.. rubric:: ' + name, ''] 20 | 21 | def _str_field_list(self, name): 22 | return [':' + name + ':'] 23 | 24 | def _str_indent(self, doc, indent=4): 25 | out = [] 26 | for line in doc: 27 | out += [' ' * indent + line] 28 | return out 29 | 30 | def _str_signature(self): 31 | return [''] 32 | if self['Signature']: 33 | return ['``%s``' % self['Signature']] + [''] 34 | else: 35 | return [''] 36 | 37 | def _str_summary(self): 38 | return self['Summary'] + [''] 39 | 40 | def _str_extended_summary(self): 41 | return self['Extended Summary'] + [''] 42 | 43 | def _str_param_list(self, name): 44 | out = [] 45 | if self[name]: 46 | out += self._str_field_list(name) 47 | out += [''] 48 | for param, param_type, desc in self[name]: 49 | out += self._str_indent(['**%s** : %s' % (param.strip(), 50 | param_type)]) 51 | out += [''] 52 | out += self._str_indent(desc, 8) 53 | out += [''] 54 | return out 55 | 56 | def _str_section(self, name): 57 | out = [] 58 | if self[name]: 59 | out += self._str_header(name) 60 | out += [''] 61 | content = textwrap.dedent("\n".join(self[name])).split("\n") 62 | out += content 63 | out += [''] 64 | return out 65 | 66 | def _str_see_also(self, func_role): 67 | out = [] 68 | if self['See Also']: 69 | see_also = super(SphinxDocString, self)._str_see_also(func_role) 70 | out = ['.. seealso::', ''] 71 | out += self._str_indent(see_also[2:]) 72 | return out 73 | 74 | def _str_warnings(self): 75 | out = [] 76 | if self['Warnings']: 77 | out = ['.. warning::', ''] 78 | out += self._str_indent(self['Warnings']) 79 | return out 80 | 81 | def _str_index(self): 82 | idx = self['index'] 83 | out = [] 84 | if len(idx) == 0: 85 | return out 86 | 87 | out += ['.. index:: %s' % idx.get('default', '')] 88 | for section, references in idx.iteritems(): 89 | if section == 'default': 90 | continue 91 | elif section == 'refguide': 92 | out += [' single: %s' % (', '.join(references))] 93 | else: 94 | out += [' %s: %s' % (section, ','.join(references))] 95 | return out 96 | 97 | def _str_references(self): 98 | out = [] 99 | if self['References']: 100 | out += self._str_header('References') 101 | if isinstance(self['References'], str): 102 | self['References'] = [self['References']] 103 | out.extend(self['References']) 104 | out += [''] 105 | return out 106 | 107 | def __str__(self, indent=0, func_role="obj"): 108 | out = [] 109 | out += self._str_signature() 110 | out += self._str_index() + [''] 111 | out += self._str_summary() 112 | out += self._str_extended_summary() 113 | for param_list in ('Parameters', 'Attributes', 'Methods', 114 | 'Returns', 'Raises'): 115 | out += self._str_param_list(param_list) 116 | out += self._str_warnings() 117 | out += self._str_see_also(func_role) 118 | out += self._str_section('Notes') 119 | out += self._str_references() 120 | out += self._str_section('Examples') 121 | out = self._str_indent(out, indent) 122 | return '\n'.join(out) 123 | 124 | 125 | class SphinxFunctionDoc(SphinxDocString, FunctionDoc): 126 | pass 127 | 128 | 129 | class SphinxClassDoc(SphinxDocString, ClassDoc): 130 | pass 131 | 132 | 133 | def get_doc_object(obj, what=None): 134 | if what is None: 135 | if inspect.isclass(obj): 136 | what = 'class' 137 | elif inspect.ismodule(obj): 138 | what = 'module' 139 | elif callable(obj): 140 | what = 'function' 141 | else: 142 | what = 'object' 143 | if what == 'class': 144 | return SphinxClassDoc(obj, '', func_doc=SphinxFunctionDoc) 145 | elif what in ('function', 'method'): 146 | return SphinxFunctionDoc(obj, '') 147 | else: 148 | return SphinxDocString(pydoc.getdoc(obj)) 149 | -------------------------------------------------------------------------------- /doc/source/sphinxext/numpydoc.py: -------------------------------------------------------------------------------- 1 | """ 2 | ======== 3 | numpydoc 4 | ======== 5 | 6 | Sphinx extension that handles docstrings in the Numpy standard format. [1] 7 | 8 | It will: 9 | 10 | - Convert Parameters etc. sections to field lists. 11 | - Convert See Also section to a See also entry. 12 | - Renumber references. 13 | - Extract the signature from the docstring, if it can't be determined 14 | otherwise. 15 | 16 | .. [1] http://projects.scipy.org/scipy/numpy/wiki/CodingStyleGuidelines#docstring-standard 17 | 18 | """ 19 | 20 | import re 21 | import pydoc 22 | import inspect 23 | import sys 24 | 25 | if sys.version_info[0] == 2: 26 | from docscrape_sphinx import get_doc_object 27 | from docscrape_sphinx import SphinxDocString 28 | else: 29 | from .docscrape_sphinx import get_doc_object 30 | from .docscrape_sphinx import SphinxDocString 31 | 32 | 33 | def mangle_docstrings(app, what, name, obj, options, lines, 34 | reference_offset=[0]): 35 | if what == 'module': 36 | # Strip top title 37 | title_re = re.compile(r'^\s*[#*=]{4,}\n[a-z0-9 -]+\n[#*=]{4,}\s*', 38 | re.I | re.S) 39 | lines[:] = title_re.sub('', "\n".join(lines)).split("\n") 40 | else: 41 | doc = get_doc_object(obj, what) 42 | lines[:] = str(doc).split("\n") 43 | 44 | if app.config.numpydoc_edit_link and hasattr(obj, '__name__') and \ 45 | obj.__name__: 46 | v = dict(full_name=obj.__name__) 47 | lines += [''] + (app.config.numpydoc_edit_link % v).split("\n") 48 | 49 | # replace reference numbers so that there are no duplicates 50 | references = [] 51 | for l in lines: 52 | l = l.strip() 53 | if l.startswith('.. ['): 54 | try: 55 | references.append(int(l[len('.. ['):l.index(']')])) 56 | except ValueError: 57 | print("WARNING: invalid reference in %s docstring" % name) 58 | 59 | # Start renaming from the biggest number, otherwise we may 60 | # overwrite references. 61 | references.sort() 62 | if references: 63 | for i, line in enumerate(lines): 64 | for r in references: 65 | new_r = reference_offset[0] + r 66 | lines[i] = lines[i].replace('[%d]_' % r, 67 | '[%d]_' % new_r) 68 | lines[i] = lines[i].replace('.. [%d]' % r, 69 | '.. [%d]' % new_r) 70 | 71 | reference_offset[0] += len(references) 72 | 73 | 74 | def mangle_signature(app, what, name, obj, options, sig, retann): 75 | # Do not try to inspect classes that don't define `__init__` 76 | if (inspect.isclass(obj) and 77 | 'initializes x; see ' in pydoc.getdoc(obj.__init__)): 78 | return '', '' 79 | 80 | if not (callable(obj) or hasattr(obj, '__argspec_is_invalid_')): 81 | return 82 | if not hasattr(obj, '__doc__'): 83 | return 84 | 85 | doc = SphinxDocString(pydoc.getdoc(obj)) 86 | if doc['Signature']: 87 | sig = re.sub("^[^(]*", "", doc['Signature']) 88 | return sig, '' 89 | 90 | 91 | def initialize(app): 92 | try: 93 | app.connect('autodoc-process-signature', mangle_signature) 94 | except: 95 | monkeypatch_sphinx_ext_autodoc() 96 | 97 | 98 | def setup(app, get_doc_object_=get_doc_object): 99 | global get_doc_object 100 | get_doc_object = get_doc_object_ 101 | 102 | app.connect('autodoc-process-docstring', mangle_docstrings) 103 | app.connect('builder-inited', initialize) 104 | app.add_config_value('numpydoc_edit_link', None, True) 105 | 106 | 107 | #------------------------------------------------------------------------------ 108 | # Monkeypatch sphinx.ext.autodoc to accept argspecless autodocs (Sphinx < 0.5) 109 | #------------------------------------------------------------------------------ 110 | 111 | 112 | def monkeypatch_sphinx_ext_autodoc(): 113 | global _original_format_signature 114 | import sphinx.ext.autodoc 115 | 116 | if sphinx.ext.autodoc.format_signature is our_format_signature: 117 | return 118 | 119 | print("[numpydoc] Monkeypatching sphinx.ext.autodoc ...") 120 | _original_format_signature = sphinx.ext.autodoc.format_signature 121 | sphinx.ext.autodoc.format_signature = our_format_signature 122 | 123 | 124 | def our_format_signature(what, obj): 125 | r = mangle_signature(None, what, None, obj, None, None, None) 126 | if r is not None: 127 | return r[0] 128 | else: 129 | return _original_format_signature(what, obj) 130 | -------------------------------------------------------------------------------- /doc/source/sphinxext/phantom_import.py: -------------------------------------------------------------------------------- 1 | """ 2 | ============== 3 | phantom_import 4 | ============== 5 | 6 | Sphinx extension to make directives from ``sphinx.ext.autodoc`` and similar 7 | extensions to use docstrings loaded from an XML file. 8 | 9 | This extension loads an XML file in the Pydocweb format [1] and 10 | creates a dummy module that contains the specified docstrings. This 11 | can be used to get the current docstrings from a Pydocweb instance 12 | without needing to rebuild the documented module. 13 | 14 | .. [1] http://code.google.com/p/pydocweb 15 | 16 | """ 17 | import imp 18 | import sys 19 | import os 20 | import inspect 21 | import re 22 | 23 | 24 | def setup(app): 25 | app.connect('builder-inited', initialize) 26 | app.add_config_value('phantom_import_file', None, True) 27 | 28 | 29 | def initialize(app): 30 | fn = app.config.phantom_import_file 31 | if (fn and os.path.isfile(fn)): 32 | print("[numpydoc] Phantom importing modules from %s ..." % fn) 33 | import_phantom_module(fn) 34 | 35 | 36 | #------------------------------------------------------------------------------ 37 | # Creating 'phantom' modules from an XML description 38 | #------------------------------------------------------------------------------ 39 | 40 | 41 | def import_phantom_module(xml_file): 42 | """ 43 | Insert a fake Python module to sys.modules, based on a XML file. 44 | 45 | The XML file is expected to conform to Pydocweb DTD. The fake 46 | module will contain dummy objects, which guarantee the following: 47 | 48 | - Docstrings are correct. 49 | - Class inheritance relationships are correct (if present in XML). 50 | - Function argspec is *NOT* correct (even if present in XML). 51 | Instead, the function signature is prepended to the function docstring. 52 | - Class attributes are *NOT* correct; instead, they are dummy objects. 53 | 54 | Parameters 55 | ---------- 56 | xml_file : str 57 | Name of an XML file to read 58 | 59 | """ 60 | import lxml.etree as etree 61 | 62 | object_cache = {} 63 | 64 | tree = etree.parse(xml_file) 65 | root = tree.getroot() 66 | 67 | # Sort items so that 68 | # - Base classes come before classes inherited from them 69 | # - Modules come before their contents 70 | all_nodes = dict([(n.attrib['id'], n) for n in root]) 71 | 72 | def _get_bases(node, recurse=False): 73 | bases = [x.attrib['ref'] for x in node.findall('base')] 74 | if recurse: 75 | j = 0 76 | while True: 77 | try: 78 | b = bases[j] 79 | except IndexError: 80 | break 81 | if b in all_nodes: 82 | bases.extend(_get_bases(all_nodes[b])) 83 | j += 1 84 | return bases 85 | 86 | type_index = ['module', 'class', 'callable', 'object'] 87 | 88 | def base_cmp(a, b): 89 | x = cmp(type_index.index(a.tag), type_index.index(b.tag)) 90 | if x != 0: 91 | return x 92 | 93 | if a.tag == 'class' and b.tag == 'class': 94 | a_bases = _get_bases(a, recurse=True) 95 | b_bases = _get_bases(b, recurse=True) 96 | x = cmp(len(a_bases), len(b_bases)) 97 | if x != 0: 98 | return x 99 | if a.attrib['id'] in b_bases: 100 | return -1 101 | if b.attrib['id'] in a_bases: 102 | return 1 103 | 104 | return cmp(a.attrib['id'].count('.'), b.attrib['id'].count('.')) 105 | 106 | nodes = root.getchildren() 107 | nodes.sort(base_cmp) 108 | 109 | # Create phantom items 110 | for node in nodes: 111 | name = node.attrib['id'] 112 | doc = (node.text or '').decode('string-escape') + "\n" 113 | if doc == "\n": 114 | doc = "" 115 | 116 | # create parent, if missing 117 | parent = name 118 | while True: 119 | parent = '.'.join(parent.split('.')[:-1]) 120 | if not parent: 121 | break 122 | if parent in object_cache: 123 | break 124 | obj = imp.new_module(parent) 125 | object_cache[parent] = obj 126 | sys.modules[parent] = obj 127 | 128 | # create object 129 | if node.tag == 'module': 130 | obj = imp.new_module(name) 131 | obj.__doc__ = doc 132 | sys.modules[name] = obj 133 | elif node.tag == 'class': 134 | bases = [object_cache[b] for b in _get_bases(node) 135 | if b in object_cache] 136 | bases.append(object) 137 | init = lambda self: None 138 | init.__doc__ = doc 139 | obj = type(name, tuple(bases), {'__doc__': doc, '__init__': init}) 140 | obj.__name__ = name.split('.')[-1] 141 | elif node.tag == 'callable': 142 | funcname = node.attrib['id'].split('.')[-1] 143 | argspec = node.attrib.get('argspec') 144 | if argspec: 145 | argspec = re.sub('^[^(]*', '', argspec) 146 | doc = "%s%s\n\n%s" % (funcname, argspec, doc) 147 | obj = lambda: 0 148 | obj.__argspec_is_invalid_ = True 149 | obj.func_name = funcname 150 | obj.__name__ = name 151 | obj.__doc__ = doc 152 | if inspect.isclass(object_cache[parent]): 153 | obj.__objclass__ = object_cache[parent] 154 | else: 155 | class Dummy(object): 156 | pass 157 | obj = Dummy() 158 | obj.__name__ = name 159 | obj.__doc__ = doc 160 | if inspect.isclass(object_cache[parent]): 161 | obj.__get__ = lambda: None 162 | object_cache[name] = obj 163 | 164 | if parent: 165 | if inspect.ismodule(object_cache[parent]): 166 | obj.__module__ = parent 167 | setattr(object_cache[parent], name.split('.')[-1], obj) 168 | 169 | # Populate items 170 | for node in root: 171 | obj = object_cache.get(node.attrib['id']) 172 | if obj is None: 173 | continue 174 | for ref in node.findall('ref'): 175 | if node.tag == 'class': 176 | if ref.attrib['ref'].startswith(node.attrib['id'] + '.'): 177 | setattr(obj, ref.attrib['name'], 178 | object_cache.get(ref.attrib['ref'])) 179 | else: 180 | setattr(obj, ref.attrib['name'], 181 | object_cache.get(ref.attrib['ref'])) 182 | -------------------------------------------------------------------------------- /doc/source/why.rst: -------------------------------------------------------------------------------- 1 | Why Python? 2 | =========== 3 | 4 | .. code-block:: python 5 | 6 | ls *.nii | python -c 'import sys, irtk; [sys.stdout.write( str(irtk.imread(line.rstrip(), dtype="float32").max())+"\n") for line in sys.stdin]' 7 | 8 | 9 | Why another Python libraries for medical imaging? 10 | ================================================= 11 | 12 | .. code-block:: python 13 | 14 | import itk 15 | 16 | pixelType = itk.UC 17 | imageType = itk.Image[pixelType, 3] 18 | readerType = itk.ImageFileReader[imageType] 19 | writerType = itk.ImageFileWriter[imageType] 20 | reader = readerType.New() 21 | reader.SetFileName( "input.nii" ) 22 | reader.Update() 23 | 24 | itk2np = itk.PyBuffer[imageType] 25 | data = itk2np.GetArrayFromImage( reader.GetOutput() ) 26 | 27 | ... 28 | 29 | 30 | .. code-block:: python 31 | 32 | import SimpleITK as sitk 33 | 34 | img = sitk.ReadImage( "input.nii" ) 35 | data = sitk.GetArrayFromImage( img ) 36 | 37 | ... 38 | 39 | output = sitk.GetImageFromArray( data ) 40 | output.SetSpacing( img.GetSpacing() ) 41 | output.SetOrigin( img.GetOrigin() ) 42 | output.SetDirection( img.GetDirection() ) 43 | sitk.WriteImage( output, "output.nii" ) 44 | 45 | .. code-block:: python 46 | 47 | import irtk 48 | 49 | img = irtk.imread( "input.nii" ) 50 | 51 | ... 52 | 53 | irtk.imwrite( "output.nii", img ) 54 | 55 | -------------------------------------------------------------------------------- /generate_templates.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | 5 | # FIXME: 6 | # update using 7 | # from string import Template 8 | 9 | output_folder = sys.argv[1] 10 | source_folder = sys.argv[2] 11 | 12 | #define IRTK_VOXEL_UNKNOWN 0 13 | #define IRTK_VOXEL_CHAR 1 14 | #define IRTK_VOXEL_UNSIGNED_CHAR 2 15 | #define IRTK_VOXEL_SHORT 3 16 | #define IRTK_VOXEL_UNSIGNED_SHORT 4 17 | #define IRTK_VOXEL_INT 5 18 | #define IRTK_VOXEL_UNSIGNED_INT 6 19 | #define IRTK_VOXEL_FLOAT 7 20 | #define IRTK_VOXEL_DOUBLE 8 21 | #define IRTK_VOXEL_RGB 9 22 | 23 | types = { 24 | "char" : "int8", 25 | "uchar" : "uint8", 26 | "short" : "int16", 27 | "ushort" : "uint16", 28 | "int" : "int32", 29 | "uint" : "uint32", 30 | "float" : "float32", 31 | "double" : "float64" 32 | } 33 | 34 | header_cpp = { 35 | """bool _imread_%s( char* filename, %s* img );""" : 2, 36 | """ 37 | bool _imwrite_%s( char* filename, 38 | %s* img, 39 | double* pixelSize, 40 | double* xAxis, 41 | double* yAxis, 42 | double* zAxis, 43 | double* origin, 44 | int* dim ); 45 | """ : 2, 46 | } 47 | 48 | templates_cpp = { 49 | """ 50 | bool _imread_%s( char* filename, 51 | %s* img ) { 52 | try { 53 | irtkGenericImage<%s> image(filename); 54 | int n = image.GetNumberOfVoxels(); 55 | %s* ptr = image.GetPointerToVoxels(); 56 | std::copy( ptr, ptr+n, img ); 57 | return true; 58 | } 59 | catch (irtkException &e) { 60 | return false; 61 | } 62 | } 63 | """ : 4, 64 | 65 | """ 66 | bool _imwrite_%s( char* filename, 67 | %s* img, 68 | double* pixelSize, 69 | double* xAxis, 70 | double* yAxis, 71 | double* zAxis, 72 | double* origin, 73 | int* dim ) { 74 | try { 75 | irtkGenericImage<%s> irtk_image; 76 | py2irtk<%s>( irtk_image, 77 | img, 78 | pixelSize, 79 | xAxis, 80 | yAxis, 81 | zAxis, 82 | origin, 83 | dim ); 84 | irtk_image.Write( filename ); 85 | return true; 86 | } 87 | catch (irtkException &e) { 88 | return false; 89 | } 90 | } 91 | """ : 4, 92 | 93 | } 94 | 95 | header_py = { 96 | """bool _imread_%s( char* filename, %s* img )""" : 2, 97 | """bool _imwrite_%s( char* filename, 98 | %s* img, 99 | double* pixelSize, 100 | double* xAxis, 101 | double* yAxis, 102 | double* zAxis, 103 | double* origin, 104 | int* dim ) 105 | """ : 2, 106 | } 107 | 108 | templates_py = { 109 | """ 110 | def imread_%s( bytes py_string, header ): 111 | cdef char* c_string = py_string 112 | cdef np.ndarray[%s, ndim=4, mode="c"] img = np.empty( (header['dim'][3], 113 | header['dim'][2], 114 | header['dim'][1], 115 | header['dim'][0]), dtype="%s" ) 116 | cdef bool success = _imread_%s( c_string, <%s*>img.data ) 117 | if not success: 118 | return False 119 | else: 120 | return img 121 | """ : (0,0,1,0,0), 122 | 123 | """ 124 | def imwrite_%s( bytes py_string, np.ndarray[%s, ndim=4, mode="c"] img, header ): 125 | cdef np.ndarray[double, ndim=1, mode="c"] pixelSize = header['pixelSize'] 126 | cdef np.ndarray[double, ndim=1, mode="c"] xAxis = header['orientation'][0] 127 | cdef np.ndarray[double, ndim=1, mode="c"] yAxis = header['orientation'][1] 128 | cdef np.ndarray[double, ndim=1, mode="c"] zAxis = header['orientation'][2] 129 | cdef np.ndarray[double, ndim=1, mode="c"] origin = header['origin'] 130 | cdef np.ndarray[int, ndim=1, mode="c"] dim = header['dim'] 131 | 132 | cdef char* c_string = py_string 133 | cdef bool success = _imwrite_%s( c_string, 134 | <%s*>img.data, 135 | pixelSize.data, 136 | xAxis.data, 137 | yAxis.data, 138 | zAxis.data, 139 | origin.data, 140 | dim.data ) 141 | return success 142 | """ : (0,0,0,0), 143 | } 144 | 145 | f = open( output_folder + "/templates.h",'wb') 146 | f.write("""#ifndef TEMPLATES_H 147 | #define TEMPLATES_H 148 | 149 | #include "irtk2cython.h"\n\n""") 150 | 151 | for t,n in header_cpp.iteritems(): 152 | for dtype in types: 153 | f.write( t % ((dtype,)*n) ) 154 | f.write("\n") 155 | f.write("\n") 156 | 157 | f.write("""#endif""") 158 | f.close() 159 | 160 | f = open( output_folder + "/templates.cc",'wb') 161 | f.write("""#include "templates.h"\n""") 162 | 163 | for t,n in templates_cpp.iteritems(): 164 | for dtype in types: 165 | f.write( t % ((dtype,)*n) ) 166 | 167 | f.close() 168 | 169 | f = open( output_folder + "/templates.pyx",'wb') 170 | f.write( 171 | """########## Automatically generated templated code ########## 172 | 173 | cdef extern from "templates.h":\n""") 174 | 175 | for t,n in header_py.iteritems(): 176 | for dtype in types: 177 | f.write(' ') 178 | f.write( t % ((dtype,)*n) ) 179 | f.write("\n") 180 | f.write("\n") 181 | 182 | for t,n in templates_py.iteritems(): 183 | for s in types.iteritems(): 184 | n2 = map( lambda x: s[x], n ) 185 | f.write( t % tuple(n2) ) 186 | 187 | f.close() 188 | 189 | 190 | # http://docs.python.org/2/distutils/apiref.html 191 | 192 | # Concatenate automatically generated files 193 | import fileinput 194 | with open(output_folder + "/_irtk.pyx", 'w') as fout: 195 | for line in fileinput.input([source_folder + "src/_irtk.pyx", 196 | output_folder + "/templates.pyx"]): 197 | fout.write(line) 198 | fout.close() 199 | -------------------------------------------------------------------------------- /include/crf.h: -------------------------------------------------------------------------------- 1 | #include "irtk2cython.h" 2 | #include "irtkCRF.h" 3 | #include "irtkSimpleGraphcut.h" 4 | 5 | #define PY_FORMAT_LONG_LONG "ll" 6 | 7 | void _crf( pixel_t* img, 8 | double* pixelSize, 9 | double* xAxis, 10 | double* yAxis, 11 | double* zAxis, 12 | double* origin, 13 | int* dim, 14 | LabelID* labels, 15 | int nb_labels, 16 | double* proba, 17 | double l, 18 | double sigma, 19 | double sigmaZ ); 20 | 21 | void _graphcut( pixel_t* img, 22 | double* pixelSize, 23 | double* xAxis, 24 | double* yAxis, 25 | double* zAxis, 26 | double* origin, 27 | int* dim, 28 | LabelID* labels, 29 | double l, 30 | double sigma, 31 | double sigmaZ ); 32 | -------------------------------------------------------------------------------- /include/drawing.h: -------------------------------------------------------------------------------- 1 | #ifndef __DRAWING_H__ 2 | #define __DRAWING_H__ 3 | 4 | #include "irtk2cython.h" 5 | 6 | void _drawSphere( unsigned char* img, 7 | int shape0, 8 | int shape1, 9 | int shape2, 10 | int x0, 11 | int y0, 12 | int z0, 13 | int rx, 14 | int ry, 15 | int rz ); 16 | 17 | #endif 18 | 19 | 20 | -------------------------------------------------------------------------------- /include/irtk2cython.h: -------------------------------------------------------------------------------- 1 | #ifndef IRTK2CYTHON_H 2 | #define IRTK2CYTHON_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | // Interpolation method 20 | #define NEAREST_NEIGHBOR 0 21 | #define LINEAR 1 22 | #define BSPLINE 2 23 | #define CSPLINE 3 24 | #define SINC 4 25 | #define SHAPE 5 26 | #define GAUSSIAN 6 27 | 28 | typedef unsigned char uchar; 29 | typedef unsigned short ushort; 30 | typedef unsigned int uint; 31 | 32 | inline size_t index( size_t i, size_t j, 33 | size_t shape0, size_t shape1 ) { 34 | return j + shape1*i; 35 | } 36 | 37 | inline size_t index( size_t i, size_t j, size_t k, 38 | size_t shape0, size_t shape1, size_t shape2 ) { 39 | return k + shape2*( j + shape1*i ); 40 | } 41 | 42 | inline size_t index( size_t i, size_t j, size_t k, size_t l, 43 | size_t shape0, size_t shape1, size_t shape2, size_t shape3 ) { 44 | return l + shape3*( k + shape2*( j + shape1*i ) ); 45 | } 46 | 47 | void Initialize(); 48 | 49 | int _get_header( char* filename, 50 | double* pixelSize, 51 | double* xAxis, 52 | double* yAxis, 53 | double* zAxis, 54 | double* origin, 55 | int* dim ); 56 | 57 | void put_attributes( irtkImageAttributes &attr, 58 | double* pixelSize, 59 | double* xAxis, 60 | double* yAxis, 61 | double* zAxis, 62 | double* origin, 63 | int* dim ); 64 | 65 | void get_attributes( irtkImageAttributes &attr, 66 | double* pixelSize, 67 | double* xAxis, 68 | double* yAxis, 69 | double* zAxis, 70 | double* origin, 71 | int* dim ); 72 | 73 | template 74 | void py2irtk_buffer( irtkGenericImage& irtk_image, 75 | dtype* img ) { 76 | int n = irtk_image.GetNumberOfVoxels(); 77 | dtype* ptr = irtk_image.GetPointerToVoxels(); 78 | for ( int i = 0; i < n; i++) 79 | ptr[i] = img[i]; 80 | } 81 | 82 | template 83 | void py2irtk( irtkGenericImage& irtk_image, 84 | dtype* img, 85 | double* pixelSize, 86 | double* xAxis, 87 | double* yAxis, 88 | double* zAxis, 89 | double* origin, 90 | int* dim ) { 91 | 92 | irtkImageAttributes attr; 93 | 94 | put_attributes( attr, 95 | pixelSize, 96 | xAxis, 97 | yAxis, 98 | zAxis, 99 | origin, 100 | dim ); 101 | 102 | irtk_image.Initialize(attr); 103 | 104 | py2irtk_buffer( irtk_image, img ); 105 | 106 | return; 107 | } 108 | 109 | template 110 | void irtk2py_buffer( irtkGenericImage& irtk_image, 111 | dtype* img ) { 112 | int n = irtk_image.GetNumberOfVoxels(); 113 | dtype* ptr = irtk_image.GetPointerToVoxels(); 114 | for ( int i = 0; i < n; i++) 115 | img[i] = ptr[i]; 116 | } 117 | 118 | template 119 | void irtk2py( irtkGenericImage& irtk_image, 120 | dtype* img, 121 | double* pixelSize, 122 | double* xAxis, 123 | double* yAxis, 124 | double* zAxis, 125 | double* origin, 126 | int* dim ) { 127 | 128 | irtkImageAttributes attr = irtk_image.GetImageAttributes(); 129 | 130 | //int new_dim[4]; 131 | get_attributes( attr, 132 | pixelSize, 133 | xAxis, 134 | yAxis, 135 | zAxis, 136 | origin, 137 | dim ); 138 | 139 | /* if ( dim[0] != new_dim[0] */ 140 | /* || dim[1] != new_dim[1] */ 141 | /* || dim[2] != new_dim[2] */ 142 | /* || dim[3] != new_dim[3] ) { */ 143 | /* std::cout << "the memory must be allocated in Python,\n" */ 144 | /* << "so dim must be known beforehand\n"; */ 145 | /* exit(1); */ 146 | /* } */ 147 | 148 | irtk2py_buffer( irtk_image, img ); 149 | 150 | return; 151 | } 152 | 153 | template 154 | void pyList2irtkVector( std::vector< irtkGenericImage >& vec, 155 | dtype* img, 156 | double* pixelSize, 157 | double* xAxis, 158 | double* yAxis, 159 | double* zAxis, 160 | double* origin, 161 | int* dim, 162 | int n ) { 163 | 164 | // clean the vector first 165 | vec.clear(); 166 | vec.reserve( n ); 167 | 168 | size_t offset = 0; 169 | for ( size_t i = 0; i < n; i++ ) { 170 | irtkGenericImage irtk_image; 171 | py2irtk( irtk_image, 172 | &img[offset], 173 | &pixelSize[4*i], 174 | &xAxis[3*i], 175 | &yAxis[3*i], 176 | &zAxis[3*i], 177 | &origin[4*i], 178 | &dim[4*i] ); 179 | offset += dim[4*i]*dim[4*i+1]*dim[4*i+2]*dim[4*i+3]; 180 | vec.push_back(irtk_image); 181 | } 182 | 183 | } 184 | 185 | template 186 | void irtkVector2pyList( std::vector< irtkGenericImage >& vec, 187 | dtype* img, 188 | double* pixelSize, 189 | double* xAxis, 190 | double* yAxis, 191 | double* zAxis, 192 | double* origin, 193 | int* dim, 194 | int& n ) { 195 | 196 | n = vec.size(); 197 | 198 | size_t offset = 0; 199 | for ( size_t i = 0; i < n; i++ ) { 200 | py2irtk( vec[i], 201 | &img[offset], 202 | &pixelSize[4*i], 203 | &xAxis[3*i], 204 | &yAxis[3*i], 205 | &zAxis[3*i], 206 | &origin[4*i], 207 | &dim[4*i] ); 208 | offset += dim[4*i]*dim[4*i+1]*dim[4*i+2]*dim[4*i+3]; 209 | } 210 | 211 | } 212 | 213 | void _resample( float* img_in, 214 | double* pixelSize, 215 | double* xAxis, 216 | double* yAxis, 217 | double* zAxis, 218 | double* origin, 219 | int* dim, 220 | double* new_pixelSize, 221 | float* img_out, 222 | int interpolation_method=LINEAR, 223 | float gaussian_parameter=1.0 ); 224 | 225 | void _gaussianBlurring( float* img_in, 226 | double* pixelSize, 227 | double* xAxis, 228 | double* yAxis, 229 | double* zAxis, 230 | double* origin, 231 | int* dim, 232 | float* img_out, 233 | double sigma ); 234 | 235 | void _gdt( float* img_in, 236 | double* pixelSize, 237 | double* xAxis, 238 | double* yAxis, 239 | double* zAxis, 240 | double* origin, 241 | int* dim, 242 | unsigned char* mask, 243 | float* img_out, 244 | float lambda ); 245 | 246 | void _anisoDiff( float* img_in, 247 | double* pixelSize, 248 | double* xAxis, 249 | double* yAxis, 250 | double* zAxis, 251 | double* origin, 252 | int* dim, 253 | float* img_out, 254 | int iterations ); 255 | 256 | irtkMatrix py2matrix( int rows, int cols, double* data ); 257 | 258 | void _write_list( float* img, 259 | double* pixelSize, 260 | double* xAxis, 261 | double* yAxis, 262 | double* zAxis, 263 | double* origin, 264 | int* dim, 265 | int n ); 266 | 267 | void _read_list( float* img, 268 | double* pixelSize, 269 | double* xAxis, 270 | double* yAxis, 271 | double* zAxis, 272 | double* origin, 273 | int* dim, 274 | int& n ); 275 | 276 | void _transform_points( double* m, double* pts, size_t n ); 277 | 278 | void _points_to_image( unsigned char* img, 279 | double* pixelSize, 280 | double* xAxis, 281 | double* yAxis, 282 | double* zAxis, 283 | double* origin, 284 | int* dim, 285 | double* pts, 286 | size_t n ); 287 | 288 | void _read_points( char *filename, 289 | vector< vector > &points ); 290 | void _write_points( char *filename, 291 | vector< vector > &points ); 292 | 293 | void _orientation( double* pixelSize, 294 | double* xAxis, 295 | double* yAxis, 296 | double* zAxis, 297 | double* origin, 298 | int* dim, 299 | int &i, int &j, int &k); 300 | 301 | #endif 302 | -------------------------------------------------------------------------------- /include/reconstruction.h: -------------------------------------------------------------------------------- 1 | #ifndef RECONSTRUCTION_H 2 | #define RECONSTRUCTION_H 3 | 4 | #include "irtk2cython.h" 5 | #include "registration.h" 6 | 7 | #include 8 | 9 | void _reconstruct( 10 | // input stacks or slices 11 | float* img, 12 | double* pixelSize, 13 | double* xAxis, 14 | double* yAxis, 15 | double* zAxis, 16 | double* origin, 17 | int* dim, 18 | 19 | // number of stacks 20 | int n, 21 | 22 | // stack ids: which stack each slice 23 | // comes from 24 | int* _stack_ids, 25 | 26 | // number of reconstruction iterations to run 27 | int iterations, 28 | 29 | // initial transformations 30 | double* tx, 31 | double* ty, 32 | double* tz, 33 | double* rx, 34 | double* ry, 35 | double* rz, 36 | 37 | // slice thickness 38 | double* _thickness, 39 | 40 | // mask (header same as template) 41 | float* mask_img, 42 | 43 | // output: reconstructed image 44 | float* reconstructed_img, 45 | double* reconstructed_pixelSize, 46 | double* reconstructed_xAxis, 47 | double* reconstructed_yAxis, 48 | double* reconstructed_zAxis, 49 | double* reconstructed_origin, 50 | int* reconstructed_dim ); 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /include/registration.h: -------------------------------------------------------------------------------- 1 | #ifndef REGISTRATION_H 2 | #define REGISTRATION_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | #include "irtk2cython.h" 9 | void rigid2py( irtkRigidTransformation &transform, 10 | double &tx, 11 | double &ty, 12 | double &tz, 13 | double &rx, 14 | double &ry, 15 | double &rz, 16 | bool invert=false ); 17 | 18 | void py2rigid( irtkRigidTransformation &transform, 19 | double tx, 20 | double ty, 21 | double tz, 22 | double rx, 23 | double ry, 24 | double rz, 25 | bool invert=false ); 26 | 27 | void affine2py( irtkAffineTransformation &transform, 28 | double &tx, 29 | double &ty, 30 | double &tz, 31 | double &rx, 32 | double &ry, 33 | double &rz, 34 | double &sx, 35 | double &sy, 36 | double &sz, 37 | double &sxy, 38 | double &syz, 39 | double &sxz, 40 | bool invert=false ); 41 | 42 | void py2affine( irtkAffineTransformation &transform, 43 | double tx, 44 | double ty, 45 | double tz, 46 | double rx, 47 | double ry, 48 | double rz, 49 | double sx, 50 | double sy, 51 | double sz, 52 | double sxy, 53 | double syz, 54 | double sxz, 55 | bool invert=false ); 56 | 57 | void pyList2rigidVector( std::vector< irtkRigidTransformation > &vec, 58 | double* tx, 59 | double* ty, 60 | double* tz, 61 | double* rx, 62 | double* ry, 63 | double* rz, 64 | int n, 65 | bool invert=false ); 66 | 67 | void rigidVector2pyList( std::vector< irtkRigidTransformation > &vec, 68 | double* tx, 69 | double* ty, 70 | double* tz, 71 | double* rx, 72 | double* ry, 73 | double* rz, 74 | bool invert=false ); 75 | 76 | void _read_rigid( char* filename, 77 | double &tx, 78 | double &ty, 79 | double &tz, 80 | double &rx, 81 | double &ry, 82 | double &rz ); 83 | 84 | void _write_rigid( char* filename, 85 | double tx, 86 | double ty, 87 | double tz, 88 | double rx, 89 | double ry, 90 | double rz ); 91 | 92 | void _transform_rigid( double tx, 93 | double ty, 94 | double tz, 95 | double rx, 96 | double ry, 97 | double rz, 98 | float* source_img, 99 | double* source_pixelSize, 100 | double* source_xAxis, 101 | double* source_yAxis, 102 | double* source_zAxis, 103 | double* source_origin, 104 | int* source_dim, 105 | float* target_img, 106 | double* target_pixelSize, 107 | double* target_xAxis, 108 | double* target_yAxis, 109 | double* target_zAxis, 110 | double* target_origin, 111 | int* target_dim, 112 | int interpolation_method=LINEAR, 113 | float gaussian_parameter=1.0 ); 114 | 115 | void _registration_rigid( short* source_img, 116 | double* source_pixelSize, 117 | double* source_xAxis, 118 | double* source_yAxis, 119 | double* source_zAxis, 120 | double* source_origin, 121 | int* source_dim, 122 | short* target_img, 123 | double* target_pixelSize, 124 | double* target_xAxis, 125 | double* target_yAxis, 126 | double* target_zAxis, 127 | double* target_origin, 128 | int* target_dim, 129 | double &tx, 130 | double &ty, 131 | double &tz, 132 | double &rx, 133 | double &ry, 134 | double &rz ); 135 | 136 | double _registration_rigid_points( double* source_points, 137 | double* target_points, 138 | int n, 139 | double &tx, 140 | double &ty, 141 | double &tz, 142 | double &rx, 143 | double &ry, 144 | double &rz ); 145 | 146 | void _read_affine( char* filename, 147 | double &tx, 148 | double &ty, 149 | double &tz, 150 | double &rx, 151 | double &ry, 152 | double &rz, 153 | double &sx, 154 | double &sy, 155 | double &sz, 156 | double &sxy, 157 | double &syz, 158 | double &sxz ); 159 | 160 | void _transform_affine( double tx, 161 | double ty, 162 | double tz, 163 | double rx, 164 | double ry, 165 | double rz, 166 | double sx, 167 | double sy, 168 | double sz, 169 | double sxy, 170 | double syz, 171 | double sxz, 172 | float* source_img, 173 | double* source_pixelSize, 174 | double* source_xAxis, 175 | double* source_yAxis, 176 | double* source_zAxis, 177 | double* source_origin, 178 | int* source_dim, 179 | float* target_img, 180 | double* target_pixelSize, 181 | double* target_xAxis, 182 | double* target_yAxis, 183 | double* target_zAxis, 184 | double* target_origin, 185 | int* target_dim, 186 | int interpolation_method, 187 | float gaussian_parameter ); 188 | 189 | double _registration_affine_points( double* source_points, 190 | double* target_points, 191 | int n, 192 | double &tx, 193 | double &ty, 194 | double &tz, 195 | double &rx, 196 | double &ry, 197 | double &rz, 198 | double &sx, 199 | double &sy, 200 | double &sz, 201 | double &sxy, 202 | double &syz, 203 | double &sxz ); 204 | 205 | void _affine_matrix( double tx, 206 | double ty, 207 | double tz, 208 | double rx, 209 | double ry, 210 | double rz, 211 | double sx, 212 | double sy, 213 | double sz, 214 | double sxy, 215 | double syz, 216 | double sxz, 217 | double* m ); 218 | 219 | void _affine_from_matrix( double &tx, 220 | double &ty, 221 | double &tz, 222 | double &rx, 223 | double &ry, 224 | double &rz, 225 | double &sx, 226 | double &sy, 227 | double &sz, 228 | double &sxy, 229 | double &syz, 230 | double &sxz, 231 | double* m ); 232 | 233 | void _write_affine( char* filename, 234 | double tx, 235 | double ty, 236 | double tz, 237 | double rx, 238 | double ry, 239 | double rz, 240 | double sx, 241 | double sy, 242 | double sz, 243 | double sxy, 244 | double syz, 245 | double sxz ); 246 | 247 | #endif 248 | -------------------------------------------------------------------------------- /include/voxellise.h: -------------------------------------------------------------------------------- 1 | #ifndef VOXELLISE_H 2 | #define VOXELLISE_H 3 | 4 | #include "irtk2cython.h" 5 | 6 | #include 7 | #include 8 | 9 | #ifdef HAS_VTK 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | void voxellise( vtkPolyData *poly, // input mesh (must be closed) 39 | irtkGenericImage &image, 40 | double value=1 ); 41 | 42 | void create_polydata( double* points, 43 | int npoints, 44 | int* triangles, 45 | int ntriangles, 46 | vtkPolyData *poly ); 47 | 48 | #endif 49 | 50 | void _voxellise( double* points, 51 | int npoints, 52 | int* triangles, 53 | int ntriangles, 54 | uchar* img, 55 | double* pixelSize, 56 | double* xAxis, 57 | double* yAxis, 58 | double* zAxis, 59 | double* origin, 60 | int* dim ); 61 | 62 | void _shrinkDisk( uchar* img, 63 | int shape0, 64 | int shape1, 65 | double* center, 66 | double radius, 67 | int steps ); 68 | 69 | void _shrinkSphere( double* points, 70 | int npoints, 71 | uchar* img, 72 | double* pixelSize, 73 | double* xAxis, 74 | double* yAxis, 75 | double* zAxis, 76 | double* origin, 77 | int* dim ); 78 | 79 | void _read_polydata( char* inputFilename, 80 | std::vector< std::vector >& points, 81 | std::vector< std::vector >& triangles ); 82 | #endif 83 | -------------------------------------------------------------------------------- /irtk/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module is a wrapper around IRTK (http://www.doc.ic.ac.uk/~dr/software/) 3 | written using Cython and a script to simulate templated code. 4 | """ 5 | 6 | import sys 7 | 8 | __all__ = [] 9 | 10 | import irtk.image 11 | from irtk.image import * 12 | import irtk.registration 13 | from irtk.registration import * 14 | __all__.extend(irtk.image.__all__) 15 | __all__.extend(irtk.registration.__all__) 16 | -------------------------------------------------------------------------------- /irtk/ext/FitEllipsoid.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.ndimage as nd 3 | from scipy.stats.mstats import mquantiles 4 | import itertools 5 | 6 | r = [-1,0, 1] 7 | neighbourhood = [] 8 | for a,b,c in itertools.product(r,r,r): 9 | if abs(a)+abs(b)+abs(c) == 3: 10 | neighbourhood.append((a,b,c)) 11 | 12 | def fit_ellipsoid( points, spacing=[1.0,1.0,1.0] ): 13 | """ Adapted from cvFitEllipse2 in 14 | OpenCV-2.4.3/modules/imgproc/src/shapedescr.cpp 15 | 16 | Ax**2 + By**2 + Cz**2 + Dxy + Exz + Fyz + Gx + Hy + Iz = 1 17 | 18 | """ 19 | 20 | if len(points) < 5: 21 | raise ValueError("Number of points should be >= 5") 22 | 23 | points = points.astype('float') 24 | points[:,0] *= spacing[2] 25 | points[:,1] *= spacing[1] 26 | points[:,2] *= spacing[0] 27 | #points = np.dot(points.astype('float'), np.array(spacing[::-1])) 28 | 29 | # first fit for parameters A - E 30 | center = points.mean(axis=0) 31 | #print "First center:", center 32 | 33 | A = np.zeros( (len(points),9), dtype='float' ) 34 | A[:,0] = - (points[:,0]-center[0]) * (points[:,0]-center[0]) # x**2 35 | A[:,1] = - (points[:,1]-center[1]) * (points[:,1]-center[1]) # x**2 36 | A[:,2] = - (points[:,2]-center[2]) * (points[:,2]-center[2]) # x**2 37 | A[:,3] = - (points[:,0]-center[0]) * (points[:,1]-center[1]) # xy 38 | A[:,4] = - (points[:,0]-center[0]) * (points[:,2]-center[2]) # xz 39 | A[:,5] = - (points[:,1]-center[1]) * (points[:,2]-center[2]) # yz 40 | A[:,6] = (points[:,0]-center[0]) # x 41 | A[:,7] = (points[:,1]-center[1]) # y 42 | A[:,8] = (points[:,2]-center[2]) # z 43 | 44 | B = np.ones( (len(points),1), dtype='float' ) * 10000 45 | 46 | x = np.linalg.lstsq( A, B )[0].flatten() 47 | 48 | # M = np.array([[x[0],x[3]/2,x[4]/2], 49 | # [x[3]/2,x[1],x[5]/2], 50 | # [x[4]/2,x[5]/2,x[2]]],dtype='float') 51 | 52 | # print M,M.shape 53 | 54 | # u, s, v = np.linalg.svd(M) 55 | 56 | # return center,s,v 57 | 58 | # now use general-form parameters A - E to find the ellipse center: 59 | # differentiate general form wrt x/y to get two equations for cx and cy 60 | 61 | A = np.zeros( (3,3), dtype='float' ) 62 | B = np.zeros( (3,1), dtype='float' ) 63 | A[0,0] = 2*x[0] # 2*A 64 | A[0,1] = x[3] # D 65 | A[0,2] = x[4] # E 66 | B[0] = x[6] # G 67 | 68 | A[1,0] = x[3] # D 69 | A[1,1] = 2*x[1] # 2*B 70 | A[1,2] = x[5] # F 71 | B[1] = x[7] # G 72 | 73 | A[2,0] = x[4] # E 74 | A[2,1] = x[5] # F 75 | A[2,2] = 2*x[2] # 2*C 76 | B[2] = x[8] # H 77 | 78 | x = np.linalg.lstsq( A, B )[0].flatten() 79 | center += x 80 | 81 | #print "Second center:", center 82 | 83 | # re-fit for parameters A - C with those center coordinates 84 | A = np.zeros( (len(points),6), dtype='float' ) 85 | A[:,0] = (points[:,0]-center[0]) * (points[:,0]-center[0]) # x**2 86 | A[:,1] = (points[:,1]-center[1]) * (points[:,1]-center[1]) # y**2 87 | A[:,2] = (points[:,2]-center[2]) * (points[:,2]-center[2]) # z**2 88 | A[:,3] = (points[:,0]-center[0]) * (points[:,1]-center[1]) # xy 89 | A[:,4] = (points[:,0]-center[0]) * (points[:,2]-center[2]) # xz 90 | A[:,5] = (points[:,1]-center[1]) * (points[:,2]-center[2]) # yz 91 | # A[:,6] = points[:,0]-center[0] # x 92 | # A[:,7] = points[:,1]-center[1] # y 93 | # A[:,8] = points[:,2]-center[2] # z 94 | 95 | B = np.ones( (len(points),1), dtype='float' ) 96 | 97 | x = np.linalg.lstsq( A, B )[0].flatten() 98 | 99 | M = np.array([[x[0],x[3]/2,x[4]/2], 100 | [x[3]/2,x[1],x[5]/2], 101 | [x[4]/2,x[5]/2,x[2]]],dtype='float') 102 | 103 | #print M,M.shape 104 | 105 | u, s, v = np.linalg.svd(M) 106 | 107 | return center,1/np.sqrt(s[::-1]),v[::-1] 108 | 109 | def fit_ellipsoid2( points, spacing=[1.0,1.0,1.0] ): 110 | points = points.astype('float') 111 | points[:,0] *= spacing[2] 112 | points[:,1] *= spacing[1] 113 | points[:,2] *= spacing[0] 114 | 115 | center = points.mean(axis=0) 116 | points -= center 117 | U, S, V = np.linalg.svd(points, full_matrices=False) 118 | 119 | # http://stackoverflow.com/questions/4801259/whats-wrong-with-my-pca 120 | #S /= len(points) - 1 121 | 122 | #print "ellipse",center, S, V 123 | #S = 1/S#**2 124 | S *= 1.96 125 | S /= np.sqrt(len(points)-1) 126 | return center,S,V 127 | #return center, 1/S[::-1]**2, V[::-1] 128 | 129 | def draw_ellipsoid( img, center, s, v, l=1, spacing=[1.0,1.0,1.0] ): 130 | spacing = np.array(spacing[::-1],dtype='float') 131 | bbox = np.array([ center - np.dot(v,(s*np.array(offset,dtype='float')).T) 132 | for offset in neighbourhood],dtype='int') 133 | z0 = max(0,np.min(bbox[:,0])) 134 | z1 = min(img.shape[0],np.max(bbox[:,0])+1) 135 | y0 = max(0,np.min(bbox[:,1])) 136 | y1 = min(img.shape[1],np.max(bbox[:,1])+1) 137 | x0 = max(0,np.min(bbox[:,2])) 138 | x1 = min(img.shape[2],np.max(bbox[:,2])+1) 139 | for z in range(z0, z1): 140 | for y in range(y0,y1): 141 | for x in range(x0,x1): 142 | p = np.array([z,y,x],dtype='float')*spacing-center 143 | p = np.dot( v, p.T) 144 | #if s[0]*p[0]**2 + s[1]*p[1]**2 + s[2]*p[2]**2 <= 1: 145 | if (p[0]/s[0])**2 + (p[1]/s[1])**2 + (p[2]/s[2])**2 <= 1: 146 | img[z,y,x] = l 147 | return img 148 | 149 | # def get_voxels(labels,raw_spacing=[1.0,1.0,1.0],selected=None): 150 | # v = [[] for i in range(np.max(labels)+1)] 151 | # obj = nd.find_objects(labels) 152 | # for i,o in enumerate(obj): 153 | # l = i+1 154 | # if selected is not None and l not in selected: 155 | # #print l, "is not in", selected 156 | # continue 157 | # if o is None: 158 | # #print "o is None" 159 | # continue 160 | # for z in range(o[0].start,o[0].stop): 161 | # for y in range(o[1].start,o[1].stop): 162 | # for x in range(o[2].start,o[2].stop): 163 | # if labels[z,y,x] == l: 164 | # v[l].append((z,y,x)) 165 | 166 | # return v 167 | 168 | def get_voxels(labels,max_label): 169 | count = np.bincount(labels.flatten()) 170 | 171 | tmp = np.unravel_index(np.argsort(labels,axis=None),labels.shape) 172 | v = [np.zeros((count[i],3),dtype='int') for i in range(max_label+1)] 173 | s = 0 174 | for i in range(max_label+1): 175 | v[i][:,0] = tmp[0][s:s+count[i]] 176 | v[i][:,1] = tmp[1][s:s+count[i]] 177 | v[i][:,2] = tmp[2][s:s+count[i]] 178 | s += count[i] 179 | 180 | return v 181 | 182 | def adjacent_labels(labels): 183 | m1 = nd.maximum_filter(labels, size=3) 184 | m1[m1==labels] = 0 185 | m2 = nd.minimum_filter(labels, size=3) 186 | m2[m2==labels] = 0 187 | m1[m2>0] = m2[m2>0] 188 | return m1 189 | 190 | def boundaries(labels,keep_labels=True): 191 | border_pixels = (nd.convolve(labels,np.ones((3,3,3),dtype='float')/27) - labels) != 0 192 | if not keep_labels: 193 | return border_pixels 194 | borders = labels.copy() 195 | borders[border_pixels==0] = 0 196 | return borders 197 | 198 | # def intensity_histogram( img, (z0,y0,x0,z1,y1,x1), center, s, v ): 199 | # hist = np.zeros(3,dtype='float') 200 | # R_max = 4*max(np.sqrt(1/s[1]),np.sqrt(1/s[2]))+1 201 | # R0 = int(R_max) 202 | # count = np.zeros(10,dtype='float') 203 | # for z in range(max(0,z0-R0), min(img.shape[0],z1+R0)): 204 | # for y in range(max(0,y0-R0),min(img.shape[1],y1+R0)): 205 | # for x in range(max(0,x0),min(img.shape[2],x1+R0)): 206 | # p = np.array([z,y,x],dtype='float') - center 207 | # p = np.dot( v, p.T) 208 | # if ( p[0]**2/(1/s[0]) 209 | # + p[1]**2/(4**2* 1/s[1]) + p[2]**2/(4**2* 1/s[2]) 210 | # <= 1 ): 211 | # R = np.sqrt(p[1]**2 + p[2]**2) 212 | # #if R < R_max: 213 | # index = int(R/R_max*3) 214 | # hist[index] += img[z,y,x] 215 | # count[index] += 1 216 | # for i in range(len(hist)): 217 | # if count[i] > 0: 218 | # hist[i] /= count[i] 219 | # hist /= np.linalg.norm(hist) 220 | # return hist 221 | 222 | # def intensity_diff( img, (z0,y0,x0,z1,y1,x1), center, s, v ): 223 | # inside = 0.0 224 | # outside = 0.0 225 | # nb_in = 0 226 | # nb_out = 0 227 | # R_max = 2*max(np.sqrt(1/s[1]),np.sqrt(1/s[2])) 228 | # R_in = np.mean([np.sqrt(1/s[1]),np.sqrt(1/s[2])]) 229 | # R0 = int(R_max) 230 | # for z in range(max(0,z0-R0), min(img.shape[0],z1+R0)): 231 | # for y in range(max(0,y0-R0),min(img.shape[1],y1+R0)): 232 | # for x in range(max(0,x0-R0),min(img.shape[2],x1+R0)): 233 | # p = np.array([z,y,x],dtype='float') - center 234 | # p = np.dot( v, p.T) 235 | # if ( p[0]**2/(1/s[0]) 236 | # + p[1]**2/(2**2* 1/s[1]) + p[2]**2/(2**2* 1/s[2]) 237 | # <= 1 ): 238 | # if ( p[0]**2/(1/s[0]) 239 | # + p[1]**2/(1/s[1]) + p[2]**2/ 1/s[2]) 240 | # <= 1 ): 241 | # R = np.sqrt(p[1]**2 + p[2]**2) 242 | # if R < R_max: 243 | # if R <= R_in: 244 | # inside += img[z,y,x] 245 | # nb_in += 1 246 | # else: 247 | # outside += img[z,y,x] 248 | # nb_out += 1 249 | 250 | # inside /= nb_in 251 | # outside /= nb_out 252 | 253 | # return (inside, outside) 254 | 255 | def features( img, labels, l, (z0,y0,x0,z1,y1,x1), center, s, v, points, n_slic ): 256 | outside = img[z0:z1,y0:y1,x0:x1].mean() 257 | d = z1 - z0 258 | h = y1 - y0 259 | w = x1 - x0 260 | zc = (z0+z1)/2 261 | yc = (y0+y1)/2 262 | xc = (x0+x1)/2 263 | outside2 = img[max(0,zc - d/2):min(img.shape[0],zc+d/2), 264 | max(0,yc - h/2):min(img.shape[1],yc+h/2), 265 | max(0,xc - w/2):min(img.shape[2],xc+w/2)].mean() 266 | voxels = img[points[:,0], 267 | points[:,1], 268 | points[:,2]] 269 | gravity_center = points.mean(axis=0) 270 | 271 | # for z in range(z0,z1): 272 | # for y in range(y0,y1): 273 | # for x in range(x0,x1): 274 | # #p = np.array([z,y,x],dtype='float') - center 275 | # # p = np.dot( v, p.T) 276 | # # if s[0]*p[0]**2 + s[1]*p[1]**2 + s[2]*p[2]**2 <= 1: 277 | # # voxels.append(img[z,y,x]) 278 | # if labels[z,y,x] == l: 279 | # voxels.append(img[z,y,x]) 280 | 281 | voxels = np.array(voxels) 282 | inside = voxels.mean() 283 | 284 | a,b,c = s#(1/np.sqrt(s))[::-1] # a,b,c are the lenghts of the semi-axes 285 | V = 4.0/3.0*np.pi*a*b*c 286 | 287 | # e1 = np.sqrt(1-(b/a)**2) 288 | # e2 = np.sqrt(1-(c/b)**2) 289 | 290 | # ratio = np.sqrt(1 - ((b+c)/(a+b+c))**2) # percentage of explained variance? 291 | 292 | nb_points = float(len(points)) 293 | return ( a/(a+b+c),b/a,c/a,c/b, 294 | (inside-outside)/(inside+0.0001),(inside-outside2)/(inside+0.0001), 295 | voxels.std(), 296 | nb_points/n_slic, 297 | nb_points/V, 298 | nb_points/(d*h*w), 299 | V/n_slic, 300 | d*h*w/V, 301 | np.linalg.norm(gravity_center-center)/c) 302 | 303 | if __name__=="__main__": 304 | test = "output/1671_slic.nii" 305 | sitk_img = sitk.ReadImage( "output/1671_resampled.nii" ) 306 | img = sitk.GetArrayFromImage( sitk_img ).astype("float") 307 | 308 | ## Contrast-stretch with saturation 309 | q = mquantiles(img.flatten(),[0.01,0.99]) 310 | img[imgq[1]] = q[1] 312 | img -= img.min() 313 | img /= img.max() 314 | 315 | sitk_img = sitk.ReadImage( test ) 316 | data = sitk.GetArrayFromImage( sitk_img ) 317 | 318 | # print nd.find_objects(data) 319 | 320 | # data = data[nd.find_objects(data)[4]] 321 | # print data 322 | 323 | labels = np.unique( data ) 324 | voxels = get_voxels(data) 325 | print "voxels done" 326 | objects = nd.find_objects(data) 327 | 328 | cyl = np.zeros(data.shape,dtype='uint8') 329 | 330 | for l in labels: 331 | if l == 0: 332 | continue 333 | print l 334 | points = np.array(voxels[l]) 335 | center,s,v = fit_ellipsoid(points) 336 | obj = objects[l-1] 337 | cyl = draw_ellipsoid(cyl, (obj[0].start,obj[1].start,obj[2].start, 338 | obj[0].stop,obj[1].stop,obj[2].stop), 339 | center,s,v,l) 340 | print "HIST:" 341 | print features( img, 342 | (obj[0].start,obj[1].start,obj[2].start, 343 | obj[0].stop,obj[1].stop,obj[2].stop), 344 | center, s, v, points,1000 ) 345 | 346 | sitk_seg = sitk.GetImageFromArray( cyl ) 347 | sitk_seg.SetSpacing( sitk_img.GetSpacing() ) 348 | sitk_seg.SetOrigin( sitk_img.GetOrigin() ) 349 | sitk_seg.SetDirection( sitk_img.GetDirection() ) 350 | sitk.WriteImage( sitk_seg, "ellipsoids.nii" ) 351 | -------------------------------------------------------------------------------- /irtk/ext/Show.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | 4 | from .. import _irtk 5 | 6 | predefined_colors = np.array( [[0,0,0], 7 | [0,0,255], 8 | [0,255,0], 9 | [255,0,0]], dtype='uint8' ) 10 | 11 | # def remap( a, colors=None ): 12 | # palette, index = np.unique(a, return_inverse = True) 13 | # if colors is None: 14 | # colors = np.random.random_integers( 0, 255, len(palette) ) 15 | # return colors[index].reshape(a.shape) 16 | 17 | def remap( a, colors=None, nb_colors=None ): 18 | if colors is None: 19 | colors = np.random.random_integers( 0, 255, nb_colors ).astype('uint8') 20 | colors[0] = 0 21 | return colors[a.flatten()].reshape(a.shape) 22 | 23 | # tmp_a = a.copy('C').astype('int32') 24 | # print tmp_a.shape, colors.shape 25 | # _irtk.remap(tmp_a, colors.copy('C') ) #colors[a.flatten()].reshape(a.shape) 26 | # return tmp_a 27 | 28 | 29 | 30 | class WindowsXYZ: 31 | def __init__(self, data, seg=None, overlay=None, colormap=None, opacity=0.5 ): 32 | data = data.astype('uint8') 33 | 34 | if len(data.shape) == 3: 35 | data = data.reshape(data.shape[0], 36 | data.shape[1], 37 | data.shape[2], 38 | 1) 39 | data = np.concatenate( [ data, 40 | data, 41 | data ], axis=3 ) 42 | 43 | if seg is not None: 44 | seg = seg.astype('int') 45 | nb_colors = seg.max()+1 46 | if colormap is None and nb_colors <= predefined_colors.shape[0]: 47 | colormap = predefined_colors 48 | if colormap is None: 49 | rgb_overlay = np.concatenate( [ remap(seg).reshape(seg.shape[0], 50 | seg.shape[1], 51 | seg.shape[2], 52 | 1).astype('uint8'), 53 | remap(seg).reshape(seg.shape[0], 54 | seg.shape[1], 55 | seg.shape[2], 56 | 1).astype('uint8'), 57 | remap(seg).reshape(seg.shape[0], 58 | seg.shape[1], 59 | seg.shape[2], 60 | 1).astype('uint8') 61 | ], 62 | axis=3 63 | ) 64 | else: 65 | rgb_overlay = colormap[seg.flatten()].reshape(seg.shape[0], 66 | seg.shape[1], 67 | seg.shape[2], 68 | 3).astype('uint8') 69 | 70 | data = (1-opacity) * data + opacity*rgb_overlay 71 | 72 | if overlay is not None: 73 | rgb_overlay = np.concatenate( 74 | [ remap(overlay, 75 | colormap[:,0]).reshape(overlay.shape[0], 76 | overlay.shape[1], 77 | overlay.shape[2], 78 | 1).astype('uint8'), 79 | remap(overlay, 80 | colormap[:,1]).reshape(overlay.shape[0], 81 | overlay.shape[1], 82 | overlay.shape[2], 83 | 1).astype('uint8'), 84 | remap(overlay, 85 | colormap[:,2]).reshape(overlay.shape[0], 86 | overlay.shape[1], 87 | overlay.shape[2], 88 | 1).astype('uint8') 89 | ], 90 | axis=3 91 | ) 92 | data = (1-opacity) * data + opacity*rgb_overlay 93 | 94 | 95 | # now, data is an RGB image 96 | self.data = data.astype('uint8') 97 | self.zyx = np.array( data.shape, dtype=int ) / 2 98 | 99 | cv2.startWindowThread() 100 | cv2.namedWindow("XY") 101 | cv2.namedWindow("XZ") 102 | cv2.namedWindow("YZ") 103 | 104 | cv2.createTrackbar('Z', 'XY', self.zyx[0], 105 | self.data.shape[0]-1, self.XY_trackbar_callback) 106 | cv2.createTrackbar('Y', 'XZ', self.zyx[1], 107 | self.data.shape[1]-1, self.XZ_trackbar_callback) 108 | cv2.createTrackbar('X', 'YZ', self.zyx[2], 109 | self.data.shape[2]-1, self.YZ_trackbar_callback) 110 | 111 | cv2.setMouseCallback("XY", self.XY_callback) 112 | cv2.setMouseCallback("XZ", self.XZ_callback) 113 | cv2.setMouseCallback("YZ", self.YZ_callback) 114 | 115 | self.show() 116 | 117 | def show(self): 118 | cv2.imshow( "XY", self.data[self.zyx[0],:,:] ) 119 | cv2.imshow( "XZ", self.data[:,self.zyx[1],:] ) 120 | cv2.imshow( "YZ", self.data[:,:,self.zyx[2]] ) 121 | 122 | def XY_trackbar_callback(self,pos): 123 | self.zyx[0] = pos # update z 124 | self.show() 125 | def XZ_trackbar_callback(self,pos): 126 | self.zyx[1] = pos # update y 127 | self.show() 128 | def YZ_trackbar_callback(self,pos): 129 | self.zyx[2] = pos # update x 130 | self.show() 131 | 132 | def XY_callback(self, event, x, y, flags, param): 133 | if event == cv2.EVENT_LBUTTONDOWN: 134 | self.zyx[1] = y 135 | self.zyx[2] = x 136 | self.show() 137 | 138 | def XZ_callback(self, event, x, y, flags, param): 139 | if event == cv2.EVENT_LBUTTONDOWN: 140 | self.zyx[0] = y 141 | self.zyx[2] = x 142 | self.show() 143 | 144 | def YZ_callback(self, event, x, y, flags, param): 145 | if event == cv2.EVENT_LBUTTONDOWN: 146 | self.zyx[0] = y 147 | self.zyx[1] = x 148 | self.show() 149 | 150 | 151 | def imshow( img, seg=None, overlay=None, colormap=None ): 152 | if overlay is not None: 153 | overlay = overlay.view(np.ndarray) 154 | if colormap is None: 155 | colormap = 'jet' 156 | if isinstance( colormap, str ): 157 | colormap = get_colormap( colormap ) 158 | if seg is not None: 159 | seg = seg.view(np.ndarray) 160 | windows = WindowsXYZ( img.view(np.ndarray), 161 | seg, 162 | overlay, colormap ) 163 | 164 | while True: 165 | ch = 0xFF & cv2.waitKey() 166 | if ( ch == 27 or ch == ord('q') # ESC 167 | or ch == ord(' ') # SPACE 168 | or ch == ord('\n') ): # ENTER 169 | break 170 | 171 | cv2.destroyAllWindows() 172 | -------------------------------------------------------------------------------- /irtk/ext/Show3D.py: -------------------------------------------------------------------------------- 1 | __all__ = [ "render" ] 2 | 3 | import vtk 4 | import numpy as np 5 | import sys 6 | 7 | from scipy.stats.mstats import mquantiles 8 | import scipy.interpolate 9 | 10 | from vtk.util.vtkConstants import * 11 | 12 | import matplotlib.pyplot as plt 13 | 14 | def numpy2VTK(img,spacing=[1.0,1.0,1.0]): 15 | # evolved from code from Stou S., 16 | # on http://www.siafoo.net/snippet/314 17 | importer = vtk.vtkImageImport() 18 | 19 | img_data = img.astype('uint8') 20 | img_string = img_data.tostring() # type short 21 | dim = img.shape 22 | 23 | importer.CopyImportVoidPointer(img_string, len(img_string)) 24 | importer.SetDataScalarType(VTK_UNSIGNED_CHAR) 25 | importer.SetNumberOfScalarComponents(1) 26 | 27 | extent = importer.GetDataExtent() 28 | importer.SetDataExtent(extent[0], extent[0] + dim[2] - 1, 29 | extent[2], extent[2] + dim[1] - 1, 30 | extent[4], extent[4] + dim[0] - 1) 31 | importer.SetWholeExtent(extent[0], extent[0] + dim[2] - 1, 32 | extent[2], extent[2] + dim[1] - 1, 33 | extent[4], extent[4] + dim[0] - 1) 34 | 35 | importer.SetDataSpacing( spacing[0], spacing[1], spacing[2]) 36 | importer.SetDataOrigin( 0,0,0 ) 37 | 38 | return importer 39 | 40 | def volumeRender(img, tf=[],spacing=[1.0,1.0,1.0]): 41 | importer = numpy2VTK(img,spacing) 42 | 43 | # Transfer Functions 44 | opacity_tf = vtk.vtkPiecewiseFunction() 45 | color_tf = vtk.vtkColorTransferFunction() 46 | 47 | if len(tf) == 0: 48 | tf.append([img.min(),0,0,0,0]) 49 | tf.append([img.max(),1,1,1,1]) 50 | 51 | for p in tf: 52 | color_tf.AddRGBPoint(p[0], p[1], p[2], p[3]) 53 | opacity_tf.AddPoint(p[0], p[4]) 54 | 55 | volMapper = vtk.vtkGPUVolumeRayCastMapper() 56 | volMapper.SetInputConnection(importer.GetOutputPort()) 57 | 58 | # The property describes how the data will look 59 | volProperty = vtk.vtkVolumeProperty() 60 | volProperty.SetColor(color_tf) 61 | volProperty.SetScalarOpacity(opacity_tf) 62 | volProperty.ShadeOn() 63 | volProperty.SetInterpolationTypeToLinear() 64 | 65 | vol = vtk.vtkVolume() 66 | vol.SetMapper(volMapper) 67 | vol.SetProperty(volProperty) 68 | 69 | return [vol] 70 | 71 | 72 | def vtk_basic( actors ): 73 | """ 74 | Create a window, renderer, interactor, add the actors and start the thing 75 | 76 | Parameters 77 | ---------- 78 | actors : list of vtkActors 79 | 80 | Returns 81 | ------- 82 | nothing 83 | """ 84 | 85 | # create a rendering window and renderer 86 | ren = vtk.vtkRenderer() 87 | renWin = vtk.vtkRenderWindow() 88 | renWin.AddRenderer(ren) 89 | renWin.SetSize(600,600) 90 | # ren.SetBackground( 1, 1, 1) 91 | 92 | # create a renderwindowinteractor 93 | iren = vtk.vtkRenderWindowInteractor() 94 | iren.SetRenderWindow(renWin) 95 | 96 | for a in actors: 97 | # assign actor to the renderer 98 | ren.AddActor(a ) 99 | 100 | # render 101 | renWin.Render() 102 | 103 | # enable user interface interactor 104 | iren.Initialize() 105 | iren.Start() 106 | 107 | 108 | def render( img, tf=None, colors=None, opacity=None ): 109 | """ 110 | tf: transfert function of the form [[voxel_value, r, g, b, opacity]] 111 | """ 112 | data = img.rescale().get_data(dtype='uint8') 113 | if colors is not None: 114 | tf = plt.cm.get_cmap(colors, 256)(range(256))*255 115 | tf = np.hstack( (np.arange(256).reshape(256,1), tf[:,:3]) ) 116 | if opacity is not None: 117 | opacity = np.array(opacity) 118 | x = opacity[:,0] 119 | y = opacity[:,1] 120 | f = scipy.interpolate.interp1d(x, y, kind='linear') 121 | tf = np.hstack( (tf, f(range(256)).reshape((256,1)) ) ) 122 | else: 123 | tf = np.hstack( (tf, 124 | np.linspace(0,1,len(tf)).reshape(len(tf),1), 125 | np.linspace(0,1,len(tf)).reshape(len(tf),1) ) ) 126 | if tf is None: 127 | q = mquantiles(data.flatten(),[0.5,0.98]) 128 | q[0]=max(q[0],1) 129 | q[1] = max(q[1],1) 130 | tf=[[0,0,0,0,0],[q[0],0,0,0,0],[q[1],1,1,1,0.5],[data.max(),1,1,1,1]] 131 | 132 | actor_list = volumeRender(data, tf=tf, spacing=img.header['pixelSize'][:3]) 133 | vtk_basic(actor_list) 134 | -------------------------------------------------------------------------------- /irtk/ext/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioMedIA/python-irtk/0ca6f94dcbe27807ce3e0c408354c47354e974bc/irtk/ext/__init__.py -------------------------------------------------------------------------------- /irtk/ext/dicomReader.py: -------------------------------------------------------------------------------- 1 | import dicom 2 | import numpy as np 3 | 4 | def load_dcm(filename): 5 | dcm = dicom.ReadFile(filename) 6 | 7 | # http://www.creatis.insa-lyon.fr/pipermail/dcmlib/2005-September/002141.html 8 | # http://www.dabsoft.ch/dicom/3/C.7.6.2.1.1/ 9 | # http://xmedcon.sourceforge.net/Docs/OrientationDicomStandard 10 | img0 = dcm[(0x5200, 0x9230)][0] # Per-frame Functional Groups Sequence 11 | spacingXY = img0[(0x0028, 0x9110)][0][(0x0028, 0x0030)].value # Pixel Spacing 12 | 13 | pos0 = img0[(0x0020, 0x9113)][0][(0x0020, 0x0032)].value # Image Position (Patient) 14 | orientation = img0[(0x0020, 0x9116)][0][(0x0020, 0x0037)].value # Image Orientation (Patient) 15 | 16 | i = 1 17 | spacingZ = 0 18 | while spacingZ == 0: 19 | img1 = dcm[(0x5200, 0x9230)][i] # Per-frame Functional Groups Sequence 20 | pos1 = img1[(0x0020, 0x9113)][0][(0x0020, 0x0032)].value # Image Position (Patient) 21 | 22 | spacingZ = np.linalg.norm(np.array(pos1) - np.array(pos0) ) 23 | i +=1 24 | 25 | dcm_spacing = [spacingXY[0],spacingXY[1],spacingZ] 26 | #dcm_spacing = [spacingZ,spacingXY[1],spacingXY[0]] 27 | 28 | print 'DICOM - spacing', dcm_spacing 29 | 30 | X = np.array([orientation[0],orientation[1],orientation[2]]) 31 | Y = np.array([orientation[3],orientation[4],orientation[5]]) 32 | Z = np.cross(X,Y) 33 | 34 | X *= dcm_spacing[0] 35 | Y *= dcm_spacing[1] 36 | Z *= dcm_spacing[2] 37 | scaling = np.diag(dcm_spacing + [1] ) 38 | dcm_affine = np.array([[X[0],Y[0],Z[0],pos0[0]], 39 | [X[1],Y[1],Z[1],pos0[1]], 40 | [X[2],Y[2],Z[2],pos0[2]], 41 | [0,0,0,1]]) 42 | 43 | #dcm_affine = np.dot( dcm_affine, scaling) 44 | 45 | 46 | data = dcm.pixel_array.astype('float') 47 | 48 | return data, dcm_affine,dcm_spacing 49 | 50 | def dcm2volume(filename): 51 | dcm = dicom.ReadFile(filename) 52 | 53 | data = dcm.pixel_array.astype('float')#[::-1,:,:] 54 | vol = [] 55 | 56 | # http://www.creatis.insa-lyon.fr/pipermail/dcmlib/2005-September/002141.html 57 | # http://www.dabsoft.ch/dicom/3/C.7.6.2.1.1/ 58 | # http://xmedcon.sourceforge.net/Docs/OrientationDicomStandard 59 | 60 | frames = dcm[(0x5200, 0x9230)].value # Per-frame Functional Groups Sequence 61 | cursor = 0 62 | length = 1 63 | #print len(frames.value) 64 | for i in range(len(frames)-1): 65 | current = frames[i] 66 | 67 | if length == 1: 68 | pos0 = current[(0x0020, 0x9113)][0][(0x0020, 0x0032)].value # Image Position (Patient) 69 | spacingXY = current[(0x0028, 0x9110)][0][(0x0028, 0x0030)].value # Pixel Spacing 70 | pos = current[(0x0020, 0x9113)][0][(0x0020, 0x0032)].value # Image Position (Patient) 71 | orientation = current[(0x0020, 0x9116)][0][(0x0020, 0x0037)].value # Image Orientation (Patient) 72 | 73 | next = frames[i+1] 74 | next_pos = next[(0x0020, 0x9113)][0][(0x0020, 0x0032)].value # Image Position (Patient) 75 | next_orientation = next[(0x0020, 0x9116)][0][(0x0020, 0x0037)].value # Image Orientation (Patient) 76 | 77 | spacingZ = np.linalg.norm(np.array(next_pos) - np.array(pos) ) 78 | 79 | if spacingZ == 0: 80 | raise ValueError('null spacing: not implemented') 81 | 82 | orientation = current[(0x0020, 0x9116)][0][(0x0020, 0x0037)].value # Image Orientation (Patient) 83 | next = frames[i+1] 84 | next_orientation = next[(0x0020, 0x9116)][0][(0x0020, 0x0037)].value # Image Orientation (Patient) 85 | 86 | if orientation == next_orientation and i < len(frames)-2: 87 | length += 1 88 | else: 89 | if i == len(frames)-2: 90 | length += 1 91 | dcm_spacing = [spacingXY[0],spacingXY[1],spacingZ] 92 | X = np.array([orientation[0],orientation[1],orientation[2]]) 93 | Y = np.array([orientation[3],orientation[4],orientation[5]]) 94 | Z = np.cross(X,Y) 95 | 96 | X *= dcm_spacing[0] 97 | Y *= dcm_spacing[1] 98 | Z *= dcm_spacing[2] 99 | scaling = np.diag(dcm_spacing + [1] ) 100 | dcm_affine = np.array([[X[0],Y[0],Z[0],pos0[0]], 101 | [X[1],Y[1],Z[1],pos0[1]], 102 | [X[2],Y[2],Z[2],pos0[2]], 103 | [0,0,0,1]]) 104 | 105 | vol.append((data[:,:,cursor:cursor+length,],dcm_affine)) 106 | cursor += length 107 | length = 1 108 | 109 | return vol 110 | 111 | def load_movie(filename): 112 | dcm = dicom.ReadFile(filename) 113 | 114 | # http://www.creatis.insa-lyon.fr/pipermail/dcmlib/2005-September/002141.html 115 | # http://www.dabsoft.ch/dicom/3/C.7.6.2.1.1/ 116 | # http://xmedcon.sourceforge.net/Docs/OrientationDicomStandard 117 | frames = dcm[(0x5200, 0x9230)].value # Per-frame Functional Groups Sequence 118 | 119 | img0 = frames[0] # Per-frame Functional Groups Sequence 120 | spacingXY = img0[(0x0028, 0x9110)][0][(0x0028, 0x0030)].value # Pixel Spacing 121 | 122 | pos0 = img0[(0x0020, 0x9113)][0][(0x0020, 0x0032)].value # Image Position (Patient) 123 | orientation = img0[(0x0020, 0x9116)][0][(0x0020, 0x0037)].value # Image Orientation (Patient) 124 | 125 | for i in range(1,len(frames)): 126 | img = frames[i] 127 | pos_i = img[(0x0020, 0x9113)][0][(0x0020, 0x0032)].value # Image Position (Patient) 128 | orientation_i = img[(0x0020, 0x9116)][0][(0x0020, 0x0037)].value # Image Orientation (Patient) 129 | if pos_i != pos0 or orientation_i != orientation: 130 | raise ValueError('this is not a movie') 131 | 132 | dcm_spacing = [spacingXY[0],spacingXY[1],0] 133 | 134 | print 'DICOM - spacing', dcm_spacing 135 | 136 | X = np.array([orientation[0],orientation[1],orientation[2]]) 137 | Y = np.array([orientation[3],orientation[4],orientation[5]]) 138 | 139 | X *= dcm_spacing[0] 140 | Y *= dcm_spacing[1] 141 | scaling = np.diag(dcm_spacing + [1] ) 142 | dcm_affine = np.array([[X[0],Y[0],0,pos0[0]], 143 | [X[1],Y[1],0,pos0[1]], 144 | [X[2],Y[2],0,pos0[2]], 145 | [0,0,0,1]]) 146 | 147 | data = dcm.pixel_array.transpose()#.astype('int') 148 | 149 | return data, dcm_affine,dcm_spacing 150 | 151 | -------------------------------------------------------------------------------- /irtk/ext/featExtract.ubu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioMedIA/python-irtk/0ca6f94dcbe27807ce3e0c408354c47354e974bc/irtk/ext/featExtract.ubu -------------------------------------------------------------------------------- /irtk/ext/opencv.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import _opencv 3 | 4 | def sift_patches( img, YX, size ): 5 | img = img.astype('uint8').copy() 6 | YX = np.array( YX, dtype='int32' ).copy() 7 | return _opencv.sift_patches( img, YX, size ) 8 | -------------------------------------------------------------------------------- /irtk/ext/reconstruction.py: -------------------------------------------------------------------------------- 1 | __all__ = [ "reconstruct" ] 2 | 3 | import numpy as np 4 | import _irtk 5 | 6 | import image 7 | from registration import RigidTransformation 8 | 9 | def reconstruct( slice_list, 10 | transformation_list, 11 | stack_ids, 12 | mask, 13 | thickness, 14 | iterations=1 ): 15 | """ 16 | No registration is performed if there is only one iteration. 17 | 18 | """ 19 | 20 | # if mask is None: 21 | # mask = image.ones( template_header, dtype='float32' ) 22 | 23 | stack_ids = np.array( stack_ids, dtype='int32' ) 24 | thickness = np.array( thickness, dtype='float64' ) 25 | 26 | n = len(slice_list) 27 | nb_pixels = 0 28 | for img in slice_list: 29 | nb_pixels += img.nb_pixels() 30 | 31 | pixelData = np.zeros( nb_pixels, dtype='float32' ) 32 | pixelSize = np.zeros( 4*n, dtype='float64' ) 33 | xAxis = np.zeros( 3*n, dtype='float64' ) 34 | yAxis = np.zeros( 3*n, dtype='float64' ) 35 | zAxis = np.zeros( 3*n, dtype='float64' ) 36 | origin = np.zeros( 4*n, dtype='float64' ) 37 | dim = np.zeros( 4*n, dtype='int32' ) 38 | 39 | tx = np.zeros( n, dtype='float64' ) 40 | ty = np.zeros( n, dtype='float64' ) 41 | tz = np.zeros( n, dtype='float64' ) 42 | rx = np.zeros( n, dtype='float64' ) 43 | ry = np.zeros( n, dtype='float64' ) 44 | rz = np.zeros( n, dtype='float64' ) 45 | 46 | offset = 0 47 | for i, img in enumerate(slice_list): 48 | pixelData[offset:offset+img.nb_pixels()] = img.flatten() 49 | offset += img.nb_pixels() 50 | pixelSize[4*i:4*(i+1)] = img.header['pixelSize'] 51 | xAxis[3*i:3*(i+1)] = img.header['orientation'][0] 52 | yAxis[3*i:3*(i+1)] = img.header['orientation'][1] 53 | zAxis[3*i:3*(i+1)] = img.header['orientation'][2] 54 | origin[4*i:4*(i+1)] = img.header['origin'] 55 | dim[4*i:4*(i+1)] = img.header['dim'] 56 | 57 | tx[i] = transformation_list[i].tx 58 | ty[i] = transformation_list[i].ty 59 | tz[i] = transformation_list[i].tz 60 | rx[i] = transformation_list[i].rx 61 | ry[i] = transformation_list[i].ry 62 | rz[i] = transformation_list[i].rz 63 | 64 | #_irtk.write_list( pixelData, pixelSize, xAxis, yAxis, zAxis, origin, dim, n ) 65 | 66 | reconstructed = _irtk.reconstruct( pixelData, 67 | pixelSize, 68 | xAxis, 69 | yAxis, 70 | zAxis, 71 | origin, 72 | dim, 73 | n, 74 | stack_ids, 75 | iterations, 76 | tx, ty, tz, 77 | rx, ry, rz, 78 | thickness, 79 | mask.get_data('float32','cython'), 80 | mask.get_header() ) 81 | 82 | new_transformations = [] 83 | for i in xrange(n): 84 | new_transformations.append( RigidTransformation( tx=tx[i], ty=ty[i], tz=tz[i], 85 | rx=rx[i], ry=ry[i], rz=rz[i] ) ) 86 | 87 | return ( image.Image(reconstructed, mask.get_header()), new_transformations ) 88 | -------------------------------------------------------------------------------- /irtk/ext/sift3d.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import csv 4 | import numpy as np 5 | import sys 6 | import os 7 | import subprocess 8 | import random 9 | import irtk 10 | 11 | def sift3d( img, file_id=None, tmp_dir='tmp' ): 12 | 13 | if file_id is None: 14 | file_id = str( random.randint(1, 1000) ) 15 | 16 | if not os.path.exists(tmp_dir): 17 | os.makedirs(tmp_dir) 18 | 19 | tmp_file = tmp_dir + '/' + str(os.getpid()) + "_" + file_id + ".nii" 20 | tmp_sift = tmp_dir + '/' + str(os.getpid()) + "_" + file_id + ".txt" 21 | irtk.imwrite( tmp_file, img ) 22 | 23 | proc = subprocess.Popen([os.path.dirname(irtk.__file__) + "/ext/featExtract.ubu", 24 | tmp_file, 25 | tmp_sift], stdout=subprocess.PIPE) 26 | (out, err) = proc.communicate() 27 | 28 | print out 29 | print err 30 | 31 | os.remove( tmp_file ) 32 | 33 | f = open(tmp_sift, "r") 34 | 35 | # skipping header 36 | line1 = f.next() 37 | line2 = f.next() 38 | line3 = f.next() 39 | 40 | titles = ["x", "y", "z", "scale", # Scale-space location 41 | "o11", "o12", "o13", "o21", "o22", "o23", "o31", "o32", "o32", # orientation 42 | "e1", "e2", "e3", # 2nd moment eigenvalues 43 | "i1" # info flag 44 | ] 45 | 46 | # descriptor 47 | for i in range(64): 48 | titles.append("d"+str(i)) 49 | 50 | reader = csv.DictReader(f, titles, delimiter='\t',quoting=csv.QUOTE_NONNUMERIC) 51 | 52 | features = [] 53 | for row in reader: 54 | descr = [] 55 | for i in range(64): 56 | descr.append(float(row["d"+str(i)])) 57 | descr = np.array( descr, dtype='float' ) 58 | features.append( ( ( int(row['x']), 59 | int(row['y']), 60 | int(row['z']) ), 61 | descr ) 62 | ) 63 | 64 | return features 65 | -------------------------------------------------------------------------------- /irtk/sitkreader.py: -------------------------------------------------------------------------------- 1 | from image import Image 2 | import SimpleITK as sitk 3 | import numpy as np 4 | 5 | def sitk_read( filename ): 6 | img = sitk.ReadImage( filename ) 7 | spacing = np.array( list(img.GetSpacing())+[1], dtype='float64' ) 8 | img = Image( sitk.GetArrayFromImage(img) ) 9 | img.header['pixelSize'] = spacing 10 | img.header['origin'][:3] += img.header['dim'][:3].astype('float')*img.header['pixelSize'][:3]/2 11 | return img 12 | -------------------------------------------------------------------------------- /irtk/utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import random 3 | import subprocess 4 | 5 | def HSVtoRGB( h, s, v ): 6 | """ 7 | from irtk/packages/rview/src/irtkColor.cc 8 | """ 9 | if s == 0: 10 | if h < 0: 11 | r = int(255.0*v) 12 | g = int(255.0*v); 13 | b = int(255.0*v); 14 | else: 15 | raise ValueError( "irtkColor::HSV: Undefined HSV color" ) 16 | 17 | else: 18 | if h == 1: 19 | h = 0 20 | h = h * 6 21 | i = int(h) 22 | f = h - i 23 | p = v * (1 - s) 24 | q = v * (1 - (s * f)) 25 | t = v * (1 - (s * (1 - f))) 26 | 27 | if i == 0: 28 | r = int(255.0*v) 29 | g = int(255.0*t) 30 | b = int(255.0*p) 31 | elif i == 1: 32 | r = int(255.0*q) 33 | g = int(255.0*v) 34 | b = int(255.0*p) 35 | elif i == 2: 36 | r = int(255.0*p) 37 | g = int(255.0*v) 38 | b = int(255.0*t) 39 | elif i == 3: 40 | r = int(255.0*p) 41 | g = int(255.0*q) 42 | b = int(255.0*v) 43 | elif i == 4: 44 | r = int(255.0*t) 45 | g = int(255.0*p) 46 | b = int(255.0*v) 47 | elif i == 5: 48 | r = int(255*v) 49 | g = int(255*p) 50 | b = int(255*q) 51 | 52 | return r, g, b 53 | 54 | def get_colormap( name, min=0, max=255 ): 55 | if name in [ "rainbow", "jet" ]: 56 | colormap = map( lambda x: HSVtoRGB(float(max - x)/float(max - min)*2.0/3.0, 57 | 1.0, 58 | 1.0 ), 59 | range(min,max+1) ) 60 | colormap = np.array( colormap, dtype='uint8' ) 61 | else: 62 | raise ValueError( "Unknown colormap: " + name ) 63 | color_dict = {} 64 | for i in xrange(min,max+1): 65 | color_dict[i] = colormap[i] 66 | return color_dict 67 | 68 | def colormap( color_dict, filename ): 69 | f = open(filename,'w') 70 | 71 | f.write('irtkSegmentTable: ' + str(len(color_dict)) + "\n") 72 | for i, (r,g,b) in color_dict.iteritems(): 73 | f.write(str(i) + ' ') 74 | f.write(str(r) + ' ') 75 | f.write(str(g) + ' ') 76 | f.write(str(b) + ' ') 77 | f.write(str(1) + ' ') 78 | f.write(str(1) + ' ') 79 | f.write(str(i) + "\n") 80 | 81 | f.close() 82 | 83 | def random_colormap(N): 84 | # http://cloford.com/resources/colours/500col.htm 85 | default_colors = np.array([[255,0,0], # green 86 | [0,255,0], # red 87 | [0,245,255], # turquoise 88 | [143,188,143], # darkseagreen 89 | [250,128,114], # salmon 90 | [218,112,214], # orchid 91 | [255,182,193], # lightpink 92 | [237,145,33], # carrot 93 | [61,89,171], # cobalt 94 | ], dtype='uint8' ) 95 | color_dict = {} 96 | for i in xrange(1,N+2): 97 | if i <= default_colors.shape[0]: 98 | color_dict[i] = default_colors[i-1] 99 | else: 100 | color_dict[i] = np.random.random_integers( 0, 255, 3 ) 101 | 102 | # 255 is a special label used for background 103 | color_dict[255] = [5,59,102] 104 | 105 | return color_dict 106 | 107 | def remap( a, color_dict=None, colors=None ): 108 | if colors is None: 109 | colors = np.zeros( (np.max(color_dict.keys())+1,3) ) 110 | for i, c in color_dict.iteritems(): 111 | colors[i] = c 112 | return colors[a.flatten()].reshape(a.shape[0], a.shape[1],3).astype('uint8') 113 | 114 | def run_cmd( cmd, verbose=False ): 115 | """ 116 | cmd is a list for subprocess.Popen(). 117 | """ 118 | if verbose: 119 | print ' '.join(cmd) 120 | proc = subprocess.Popen( cmd, stdout=subprocess.PIPE) 121 | 122 | (out, err) = proc.communicate() 123 | 124 | if out is not None: 125 | print out 126 | if err is not None: 127 | print err 128 | 129 | -------------------------------------------------------------------------------- /irtk/vtk2irtk.py: -------------------------------------------------------------------------------- 1 | __all__ = [ "voxellise", 2 | "shrinkDisk", 3 | "shrinkSphere" ] 4 | 5 | import image 6 | import _irtk 7 | import numpy as np 8 | 9 | def voxellise( points, triangles, header=None, pixelSize=[1,1,1,1] ): 10 | points = np.array( points, dtype='float64', order='C' ) 11 | triangles = np.array( triangles, dtype='int32', order='C' ) 12 | 13 | if header is None: 14 | pixelSize = np.array( pixelSize, dtype='float64') 15 | x_min, y_min, z_min = points.min(axis=0) - pixelSize[:3] 16 | x_max, y_max, z_max = points.max(axis=0) + pixelSize[:3] 17 | origin = [x_min + (x_max-x_min)/2, 18 | y_min + (y_max-y_min)/2, 19 | z_min + (z_max-z_min)/2, 20 | 0] 21 | dim = [ (x_max - x_min) / pixelSize[0] + 1, 22 | (y_max - y_min) / pixelSize[1] + 1, 23 | (z_max - z_min) / pixelSize[2] + 1, 24 | 1] 25 | header = image.new_header( origin=origin, 26 | dim=dim, 27 | pixelSize=pixelSize ) 28 | 29 | img = _irtk.voxellise( points, triangles, header ) 30 | 31 | return image.Image( img, header ) 32 | 33 | def read_polydata( filename ): 34 | return _irtk.read_polydata(filename) 35 | 36 | def shrinkDisk( img, 37 | center=None, 38 | radius=None, 39 | steps=50 ): 40 | if center is None: 41 | center = np.array([float(img.shape[0])/2, 42 | float(img.shape[1])/2], 43 | dtype='float64') 44 | if radius is None: 45 | radius = float(img.shape[0])/2 46 | img = img.astype('uint8').copy() 47 | center = np.array( center, dtype='float64' ).copy() 48 | return _irtk.shrinkDisk(img, center, radius, steps ) 49 | 50 | def shrinkSphere( points, header ): 51 | img = _irtk.shrinkSphere( points, header ) 52 | return image.Image( img, header ) 53 | -------------------------------------------------------------------------------- /scripts/convert.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import irtk 4 | from irtk.sitkreader import sitk_read 5 | import sys 6 | 7 | input_file = sys.argv[1] 8 | output_file = sys.argv[2] 9 | 10 | img = sitk_read( input_file ) 11 | print img.header, img.shape 12 | 13 | irtk.imwrite(output_file,img) 14 | 15 | 16 | -------------------------------------------------------------------------------- /scripts/decrop.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import SimpleITK as sitk 4 | import numpy as np 5 | import cv2 6 | 7 | import sys 8 | 9 | shape = map( int, sys.argv[1:4] ) 10 | z = int(sys.argv[4]) 11 | y = int(sys.argv[5]) 12 | x = int(sys.argv[6]) 13 | 14 | f = sys.argv[7] 15 | sitk_img = sitk.ReadImage( f ) 16 | data = sitk.GetArrayFromImage( sitk_img ) 17 | 18 | # ref = sys.argv[9] 19 | # sitk_ref = sitk.ReadImage( f ) 20 | 21 | new_data = np.zeros( shape, dtype='int32' ) 22 | new_data[z:z+data.shape[0], 23 | y:y+data.shape[1], 24 | x:x+data.shape[2]] = data 25 | new_img = sitk.GetImageFromArray( new_data ) 26 | new_img.SetDirection( sitk_img.GetDirection() ) 27 | new_img.SetOrigin( sitk_img.GetOrigin() ) 28 | new_img.SetSpacing( sitk_img.GetSpacing() ) 29 | sitk.WriteImage( new_img, sys.argv[8] ) 30 | -------------------------------------------------------------------------------- /scripts/find_template.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import SimpleITK as sitk 4 | import numpy as np 5 | import cv2 6 | 7 | import sys 8 | 9 | from scipy.stats.mstats import mquantiles 10 | from skimage.feature import match_template 11 | 12 | full_file = sys.argv[1] 13 | cropped_file = sys.argv[2] 14 | 15 | full_img = sitk.ReadImage( full_file ) 16 | full_data = sitk.GetArrayFromImage( full_img ).astype("float32") 17 | 18 | cropped_img = sitk.ReadImage( cropped_file ) 19 | cropped_data = sitk.GetArrayFromImage( cropped_img ).astype("float32") 20 | 21 | offset = cropped_data.shape[0]/2 22 | cropped_data = cropped_data[offset] 23 | 24 | res = [] 25 | for z in range(full_data.shape[0]): 26 | res.append( match_template( full_data[z], cropped_data, pad_input=False ) ) 27 | 28 | res = np.array(res) 29 | print res.max() 30 | z,y,x = np.unravel_index( np.argmax(res), res.shape ) 31 | z = z - offset 32 | 33 | print z,y,x 34 | 35 | print ' '.join( map(str, [full_data.shape[0], 36 | full_data.shape[1], 37 | full_data.shape[2], 38 | z, 39 | y, 40 | x]) ) 41 | 42 | -------------------------------------------------------------------------------- /scripts/flip.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import SimpleITK as sitk 4 | import numpy as np 5 | import cv2 6 | 7 | import sys 8 | 9 | axis = int(sys.argv[1]) 10 | 11 | f = sys.argv[2] 12 | sitk_img = sitk.ReadImage( f ) 13 | data = sitk.GetArrayFromImage( sitk_img ) 14 | 15 | if axis == 0: 16 | new_data = data[::-1,:,:].copy() 17 | elif axis == 1: 18 | new_data = data[:,::-1,:].copy() 19 | else: 20 | new_data = data[:,:,::-1].copy() 21 | 22 | new_img = sitk.GetImageFromArray( new_data ) 23 | new_img.SetDirection( sitk_img.GetDirection() ) 24 | new_img.SetOrigin( sitk_img.GetOrigin() ) 25 | new_img.SetSpacing( sitk_img.GetSpacing() ) 26 | sitk.WriteImage( new_img, sys.argv[3] ) 27 | -------------------------------------------------------------------------------- /scripts/gcut.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | import numpy as np 5 | 6 | import irtk 7 | import scipy.ndimage as nd 8 | 9 | def get_noiseXY(img): 10 | img = img.astype('float32') 11 | new_img = np.zeros(img.shape,dtype='float32') 12 | for z in xrange(img.shape[0]): 13 | new_img[z] = nd.gaussian_filter( img[z], 2, mode='reflect' ) 14 | noise = img - new_img 15 | #print "Noise XY:", noise.std(), img.std() 16 | return noise.std() 17 | 18 | def get_noiseZ(img): 19 | img = img.astype('float32') 20 | new_img = np.zeros(img.shape,dtype='float32') 21 | for x in xrange(img.shape[2]): 22 | new_img[:,:,x] = nd.gaussian_filter( img[:,:,x], 2, mode='reflect' ) 23 | noise = img - new_img 24 | #print "Noise Z:", noise.std(), img.std() 25 | return noise.std() 26 | 27 | output_filename = sys.argv[3] 28 | 29 | img = irtk.imread( sys.argv[1], dtype='float64' ).saturate() 30 | mask = irtk.imread( sys.argv[2], dtype='int16' ) 31 | mask = irtk.Image(mask,img.get_header()) 32 | 33 | # crop 34 | x_min,y_min,z_min,x_max,y_max,z_max = mask.bbox() 35 | mask = mask[z_min:z_max+1, 36 | y_min:y_max+1, 37 | x_min:x_max+1] 38 | tmp_img = img[z_min:z_max+1, 39 | y_min:y_max+1, 40 | x_min:x_max+1] 41 | 42 | 43 | downsampled_img = tmp_img.resample(2) 44 | mask = mask.transform(target=downsampled_img,interpolation='nearest') 45 | 46 | seg = irtk.graphcut( downsampled_img, mask, 47 | sigma=get_noiseXY(downsampled_img), 48 | sigmaZ=get_noiseZ(downsampled_img) ) 49 | 50 | irtk.imwrite( sys.argv[3], seg.transform(target=img,interpolation='nearest') ) 51 | 52 | 53 | -------------------------------------------------------------------------------- /scripts/hull.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | import numpy as np 5 | import irtk 6 | 7 | from pyhull.convex_hull import ConvexHull 8 | from irtk.vtk2irtk import voxellise 9 | 10 | seg = irtk.imread(sys.argv[1]) 11 | output = sys.argv[2] 12 | 13 | ZYX = np.transpose(np.nonzero(seg)) 14 | pts = seg.ImageToWorld( ZYX[:,::-1] ) 15 | hull = ConvexHull(pts) 16 | 17 | img = voxellise( hull.points, hull.vertices, header=seg.get_header() ) 18 | 19 | irtk.imwrite( output, img ) 20 | -------------------------------------------------------------------------------- /scripts/polydata2nifti.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import irtk 4 | from irtk.vtk2irtk import read_polydata, voxellise 5 | from irtk.sitkreader import sitk_read 6 | import sys 7 | 8 | vtk_file = sys.argv[1] 9 | img_file = sys.argv[2] 10 | nifti_file = sys.argv[3] 11 | 12 | points,triangles = read_polydata( vtk_file ) 13 | 14 | img = sitk_read( img_file ) 15 | print img.header, img.shape 16 | 17 | img = voxellise(points,triangles,img.get_header()) 18 | 19 | irtk.imwrite(nifti_file,img) 20 | 21 | 22 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name = "irtk", 5 | packages=["irtk"], 6 | version = "1.0", 7 | #data_files = [ ('irtk', ['build/_irtk.so']) ], 8 | #package_data = { 'irtk' : ['build/_irtk.so'] }, 9 | package_data = { 'irtk' : ['irtk/_irtk.so'] }, 10 | include_package_data=True, 11 | author = 'Kevin Keraudren', 12 | description = 'Cython based wrapper for IRTK', 13 | license = 'GPLv2', 14 | keywords = 'IRTK cython', 15 | url = 'https://github.com/BioMedIA/python-irtk' 16 | ) 17 | -------------------------------------------------------------------------------- /src/crf.cc: -------------------------------------------------------------------------------- 1 | #include "crf.h" 2 | 3 | void _crf( pixel_t* img, 4 | double* pixelSize, 5 | double* xAxis, 6 | double* yAxis, 7 | double* zAxis, 8 | double* origin, 9 | int* dim, 10 | LabelID* labels, 11 | int nb_labels, 12 | double* proba, 13 | double l, 14 | double sigma, 15 | double sigmaZ ) { 16 | 17 | irtkGenericImage irtk_image; 18 | py2irtk( irtk_image, 19 | img, 20 | pixelSize, 21 | xAxis, 22 | yAxis, 23 | zAxis, 24 | origin, 25 | dim ); 26 | 27 | irtkGenericImage irtk_labels; 28 | py2irtk( irtk_labels, 29 | labels, 30 | pixelSize, 31 | xAxis, 32 | yAxis, 33 | zAxis, 34 | origin, 35 | dim ); 36 | 37 | dim[3] = nb_labels; 38 | irtkGenericImage irtk_proba; 39 | py2irtk( irtk_proba, 40 | proba, 41 | pixelSize, 42 | xAxis, 43 | yAxis, 44 | zAxis, 45 | origin, 46 | dim ); 47 | 48 | irtkCRF crf( irtk_image, 49 | irtk_labels, 50 | irtk_proba ); 51 | crf.SetLambda( l ); 52 | crf.SetSigma( sigma ); 53 | crf.SetSigmaZ( sigmaZ ); 54 | crf.Run(); 55 | 56 | dim[3] = 1; 57 | irtk2py( irtk_labels, 58 | labels, 59 | pixelSize, 60 | xAxis, 61 | yAxis, 62 | zAxis, 63 | origin, 64 | dim ); 65 | } 66 | 67 | void _graphcut( pixel_t* img, 68 | double* pixelSize, 69 | double* xAxis, 70 | double* yAxis, 71 | double* zAxis, 72 | double* origin, 73 | int* dim, 74 | LabelID* labels, 75 | double l, 76 | double sigma, 77 | double sigmaZ ) { 78 | 79 | irtkGenericImage irtk_image; 80 | py2irtk( irtk_image, 81 | img, 82 | pixelSize, 83 | xAxis, 84 | yAxis, 85 | zAxis, 86 | origin, 87 | dim ); 88 | 89 | irtkGenericImage irtk_labels; 90 | py2irtk( irtk_labels, 91 | labels, 92 | pixelSize, 93 | xAxis, 94 | yAxis, 95 | zAxis, 96 | origin, 97 | dim ); 98 | 99 | irtkSimpleGraphcut graphcut( irtk_image, 100 | irtk_labels ); 101 | graphcut.SetSigma( sigma ); 102 | graphcut.SetSigmaZ( sigmaZ ); 103 | graphcut.Run(); 104 | 105 | irtk2py( irtk_labels, 106 | labels, 107 | pixelSize, 108 | xAxis, 109 | yAxis, 110 | zAxis, 111 | origin, 112 | dim ); 113 | } 114 | -------------------------------------------------------------------------------- /src/drawing.cc: -------------------------------------------------------------------------------- 1 | #include "drawing.h" 2 | 3 | void _drawSphere( unsigned char* img, 4 | int shape0, 5 | int shape1, 6 | int shape2, 7 | int x0, 8 | int y0, 9 | int z0, 10 | int rx, 11 | int ry, 12 | int rz ) { 13 | int rx2 = rx*rx; 14 | int ry2 = ry*ry; 15 | int rz2 = rz*rz; 16 | int x, y, z; 17 | for ( int dz = -rz; dz <= rz; dz++ ) 18 | for ( int dy = -ry; dy <= ry; dy++ ) 19 | for ( int dx = -rx; dx <= rx; dx++ ) { 20 | x = x0 + dx; 21 | y = y0 + dy; 22 | z = z0 + dz; 23 | if ( z >= 0 && z < shape0 24 | && y >= 0 && y < shape1 25 | && x >= 0 && x < shape2 ) 26 | if ( float(dx*dx)/rx2 27 | + float(dy*dy)/ry2 28 | + float(dz*dz)/rz2 <= 1 ) 29 | img[index(z,y,x,shape0,shape1,shape2)] = 1; 30 | } 31 | 32 | // if ( x*x + y*y + z*z <= rx2 ) { 33 | // cout << "setting to 1\n"; 34 | // img[index(z,y,x,shape0,shape1,shape2)] = 1; 35 | // } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/irtk2cython.cc: -------------------------------------------------------------------------------- 1 | #include "irtk2cython.h" 2 | 3 | void Initialize() { 4 | // turn off the synchronization of iostream objects and cstdio streams 5 | // for increased speed 6 | std::ios_base::sync_with_stdio(false); 7 | } 8 | 9 | int _get_header( char* filename, 10 | double* pixelSize, 11 | double* xAxis, 12 | double* yAxis, 13 | double* zAxis, 14 | double* origin, 15 | int* dim ) { 16 | try { 17 | irtkFileToImage *reader = irtkFileToImage::New(filename); 18 | 19 | irtkImageAttributes attr = reader->GetImageAttributes(); 20 | get_attributes( attr, 21 | pixelSize, 22 | xAxis, 23 | yAxis, 24 | zAxis, 25 | origin, 26 | dim ); 27 | 28 | int dtype = reader->GetDataType(); 29 | 30 | delete reader; 31 | 32 | return dtype; 33 | } 34 | catch ( irtkException &e ) { 35 | return -1; 36 | } 37 | } 38 | 39 | void put_attributes( irtkImageAttributes &attr, 40 | double* pixelSize, 41 | double* xAxis, 42 | double* yAxis, 43 | double* zAxis, 44 | double* origin, 45 | int* dim ) { 46 | // dim 47 | attr._x = dim[0]; 48 | attr._y = dim[1]; 49 | attr._z = dim[2]; 50 | attr._t = dim[3]; 51 | 52 | // voxel size 53 | attr._dx = pixelSize[0]; 54 | attr._dy = pixelSize[1]; 55 | attr._dz = pixelSize[2]; 56 | attr._dt = pixelSize[3]; 57 | 58 | // origin 59 | attr._xorigin = origin[0]; 60 | attr._yorigin = origin[1]; 61 | attr._zorigin = origin[2]; 62 | attr._torigin = origin[3]; 63 | 64 | // x-axis 65 | attr._xaxis[0] = xAxis[0]; 66 | attr._xaxis[1] = xAxis[1]; 67 | attr._xaxis[2] = xAxis[2]; 68 | 69 | // y-axis 70 | attr._yaxis[0] = yAxis[0]; 71 | attr._yaxis[1] = yAxis[1]; 72 | attr._yaxis[2] = yAxis[2]; 73 | 74 | // z-axis 75 | attr._zaxis[0] = zAxis[0]; 76 | attr._zaxis[1] = zAxis[1]; 77 | attr._zaxis[2] = zAxis[2]; 78 | } 79 | 80 | void get_attributes( irtkImageAttributes &attr, 81 | double* pixelSize, 82 | double* xAxis, 83 | double* yAxis, 84 | double* zAxis, 85 | double* origin, 86 | int* dim ) { 87 | // dim 88 | dim[0] = attr._x; 89 | dim[1] = attr._y; 90 | dim[2] = attr._z; 91 | dim[3] = attr._t; 92 | 93 | // voxel size 94 | pixelSize[0] = attr._dx; 95 | pixelSize[1] = attr._dy; 96 | pixelSize[2] = attr._dz; 97 | pixelSize[3] = attr._dt; 98 | 99 | // origin 100 | origin[0] = attr._xorigin; 101 | origin[1] = attr._yorigin; 102 | origin[2] = attr._zorigin; 103 | origin[3] = attr._torigin; 104 | 105 | // x-axis 106 | xAxis[0] = attr._xaxis[0]; 107 | xAxis[1] = attr._xaxis[1]; 108 | xAxis[2] = attr._xaxis[2]; 109 | 110 | // y-axis 111 | yAxis[0] = attr._yaxis[0]; 112 | yAxis[1] = attr._yaxis[1]; 113 | yAxis[2] = attr._yaxis[2]; 114 | 115 | // z-axis 116 | zAxis[0] = attr._zaxis[0]; 117 | zAxis[1] = attr._zaxis[1]; 118 | zAxis[2] = attr._zaxis[2]; 119 | } 120 | 121 | void _resample( float* img_in, 122 | double* pixelSize, 123 | double* xAxis, 124 | double* yAxis, 125 | double* zAxis, 126 | double* origin, 127 | int* dim, 128 | double* new_pixelSize, 129 | float* img_out, 130 | int interpolation_method, 131 | float gaussian_parameter ) { 132 | 133 | irtkGenericImage irtk_image;// = new irtkGenericImage; 134 | irtkImageFunction *interpolator = NULL; 135 | 136 | switch (interpolation_method) { 137 | 138 | case NEAREST_NEIGHBOR: 139 | { interpolator = new irtkNearestNeighborInterpolateImageFunction; } 140 | break; 141 | 142 | case LINEAR: 143 | { interpolator = new irtkLinearInterpolateImageFunction; } 144 | break; 145 | 146 | case BSPLINE: 147 | { interpolator = new irtkBSplineInterpolateImageFunction; } 148 | break; 149 | 150 | case CSPLINE: 151 | { interpolator = new irtkCSplineInterpolateImageFunction; } 152 | break; 153 | 154 | case SINC: 155 | { interpolator = new irtkSincInterpolateImageFunction; } 156 | break; 157 | 158 | case SHAPE: 159 | { interpolator = new irtkShapeBasedInterpolateImageFunction; } 160 | break; 161 | 162 | case GAUSSIAN: 163 | { interpolator = new irtkGaussianInterpolateImageFunction(gaussian_parameter); } 164 | break; 165 | 166 | default: 167 | cout << "Unknown interpolation method" << endl; 168 | } 169 | 170 | py2irtk( irtk_image, 171 | img_in, 172 | pixelSize, 173 | xAxis, 174 | yAxis, 175 | zAxis, 176 | origin, 177 | dim ); 178 | 179 | irtkResampling resampling( new_pixelSize[0], 180 | new_pixelSize[1], 181 | new_pixelSize[2] ); 182 | resampling.SetInput ( &irtk_image ); 183 | resampling.SetOutput( &irtk_image ); 184 | resampling.SetInterpolator( interpolator ); 185 | resampling.Run(); 186 | 187 | irtk2py( irtk_image, 188 | img_out, 189 | pixelSize, 190 | xAxis, 191 | yAxis, 192 | zAxis, 193 | origin, 194 | dim ); 195 | } 196 | 197 | void _gaussianBlurring( float* img_in, 198 | double* pixelSize, 199 | double* xAxis, 200 | double* yAxis, 201 | double* zAxis, 202 | double* origin, 203 | int* dim, 204 | float* img_out, 205 | double sigma ) { 206 | 207 | irtkGenericImage irtk_image; 208 | py2irtk( irtk_image, 209 | img_in, 210 | pixelSize, 211 | xAxis, 212 | yAxis, 213 | zAxis, 214 | origin, 215 | dim ); 216 | 217 | irtkGaussianBlurring gb(sigma); 218 | gb.SetInput(&irtk_image); 219 | gb.SetOutput(&irtk_image); 220 | gb.Run(); 221 | 222 | irtk2py( irtk_image, 223 | img_out, 224 | pixelSize, 225 | xAxis, 226 | yAxis, 227 | zAxis, 228 | origin, 229 | dim ); 230 | } 231 | 232 | void _gdt( float* img_in, 233 | double* pixelSize, 234 | double* xAxis, 235 | double* yAxis, 236 | double* zAxis, 237 | double* origin, 238 | int* dim, 239 | unsigned char* mask, 240 | float* img_out, 241 | float lambda ) { 242 | 243 | irtkGenericImage irtk_image; 244 | py2irtk( irtk_image, 245 | img_in, 246 | pixelSize, 247 | xAxis, 248 | yAxis, 249 | zAxis, 250 | origin, 251 | dim ); 252 | 253 | irtkGenericImage irtk_mask; 254 | py2irtk( irtk_mask, 255 | mask, 256 | pixelSize, 257 | xAxis, 258 | yAxis, 259 | zAxis, 260 | origin, 261 | dim ); 262 | 263 | irtkGenericImage distanceMap; 264 | irtkGDT gdt_filter(irtk_image,irtk_mask,distanceMap); 265 | gdt_filter.SetLambda(lambda); 266 | gdt_filter.Run(); 267 | 268 | //gdt_filter.GetOutput(irtk_image); 269 | 270 | irtk2py( distanceMap, 271 | img_out, 272 | pixelSize, 273 | xAxis, 274 | yAxis, 275 | zAxis, 276 | origin, 277 | dim ); 278 | } 279 | 280 | void _anisoDiff( float* img_in, 281 | double* pixelSize, 282 | double* xAxis, 283 | double* yAxis, 284 | double* zAxis, 285 | double* origin, 286 | int* dim, 287 | float* img_out, 288 | int iterations ) { 289 | 290 | irtkGenericImage irtk_image; 291 | py2irtk( irtk_image, 292 | img_in, 293 | pixelSize, 294 | xAxis, 295 | yAxis, 296 | zAxis, 297 | origin, 298 | dim ); 299 | 300 | anisoDiffusion anisodiff; 301 | anisodiff.SetInput(&irtk_image); 302 | anisodiff.SetOutput(&irtk_image); 303 | anisodiff.ITERATIONS_NB = iterations; 304 | anisodiff.Run(); 305 | 306 | irtk2py( irtk_image, 307 | img_out, 308 | pixelSize, 309 | xAxis, 310 | yAxis, 311 | zAxis, 312 | origin, 313 | dim ); 314 | } 315 | 316 | irtkMatrix py2matrix( int rows, int cols, double* data ) { 317 | irtkMatrix matrix(rows, cols); 318 | int i, j; 319 | for ( i = 0; i < rows; i++ ) 320 | for ( j = 0; j < cols; j++ ) 321 | matrix(i,j) = data[index(i,j,rows,cols)]; 322 | 323 | return matrix; 324 | } 325 | 326 | // test function 327 | void _write_list( float* img, 328 | double* pixelSize, 329 | double* xAxis, 330 | double* yAxis, 331 | double* zAxis, 332 | double* origin, 333 | int* dim, 334 | int n ) { 335 | std::vector< irtkGenericImage > vec; 336 | pyList2irtkVector( vec, 337 | img, 338 | pixelSize, 339 | xAxis, 340 | yAxis, 341 | zAxis, 342 | origin, 343 | dim, 344 | n ); 345 | 346 | 347 | for ( int i = 0; i < n; i++ ) { 348 | std::stringstream ss; 349 | ss << "file" << i << ".nii"; 350 | vec[i].Write( ss.str().c_str() ); 351 | } 352 | 353 | } 354 | 355 | // test function 356 | void _read_list( float* img, 357 | double* pixelSize, 358 | double* xAxis, 359 | double* yAxis, 360 | double* zAxis, 361 | double* origin, 362 | int* dim, 363 | int& n ) { 364 | // we need to know the number of pixels beforehand, 365 | // or a maximal number of pixels for Python to allocate memory... 366 | std::vector< irtkGenericImage > vec; 367 | for ( int i = 0; i < 3; i++ ) { 368 | irtkGenericImage irtk_image; 369 | std::stringstream ss; 370 | ss << "file" << i << ".nii"; 371 | irtk_image.Read( ss.str().c_str() ); 372 | vec.push_back( irtk_image ); 373 | } 374 | irtkVector2pyList( vec, 375 | img, 376 | pixelSize, 377 | xAxis, 378 | yAxis, 379 | zAxis, 380 | origin, 381 | dim, 382 | n ); 383 | 384 | } 385 | 386 | void _transform_points( double* m, double* pts, size_t n ) { 387 | double tmp_pt[3]; 388 | for ( size_t i = 0; i < n; i++ ) { 389 | tmp_pt[0] = m[index(0,0,4,4)] * pts[index(i,0,n,3)] + m[index(0,1,4,4)] * pts[index(i,1,n,3)] + m[index(0,2,4,4)] * pts[index(i,2,n,3)] + m[index(0,3,4,4)]; 390 | tmp_pt[1] = m[index(1,0,4,4)] * pts[index(i,0,n,3)] + m[index(1,1,4,4)] * pts[index(i,1,n,3)] + m[index(1,2,4,4)] * pts[index(i,2,n,3)] + m[index(1,3,4,4)]; 391 | tmp_pt[2] = m[index(2,0,4,4)] * pts[index(i,0,n,3)] + m[index(2,1,4,4)] * pts[index(i,1,n,3)] + m[index(2,2,4,4)] * pts[index(i,2,n,3)] + m[index(2,3,4,4)]; 392 | pts[index(i,0,n,3)] = tmp_pt[0]; 393 | pts[index(i,1,n,3)] = tmp_pt[1]; 394 | pts[index(i,2,n,3)] = tmp_pt[2]; 395 | } 396 | } 397 | 398 | void _points_to_image( unsigned char* img, 399 | double* pixelSize, 400 | double* xAxis, 401 | double* yAxis, 402 | double* zAxis, 403 | double* origin, 404 | int* dim, 405 | double* pts, 406 | size_t n ) { 407 | 408 | irtkGenericImage irtk_image; 409 | py2irtk( irtk_image, 410 | img, 411 | pixelSize, 412 | xAxis, 413 | yAxis, 414 | zAxis, 415 | origin, 416 | dim ); 417 | 418 | double pt[3]; 419 | for ( size_t i = 0; i < n; i++ ) { 420 | pt[0] = pts[index(i,0,n,3)]; 421 | pt[1] = pts[index(i,1,n,3)]; 422 | pt[2] = pts[index(i,2,n,3)]; 423 | irtk_image.WorldToImage( pt[0], pt[1], pt[2] ); 424 | if ( pt[0] >= 0 && pt[0] < irtk_image.GetX() 425 | && pt[1] >= 0 && pt[1] < irtk_image.GetY() 426 | && pt[2] >= 0 && pt[2] < irtk_image.GetZ() ) 427 | irtk_image( pt[0], pt[1], pt[2] ) = 1; 428 | } 429 | 430 | irtk2py( irtk_image, 431 | img, 432 | pixelSize, 433 | xAxis, 434 | yAxis, 435 | zAxis, 436 | origin, 437 | dim ); 438 | } 439 | 440 | void _read_points( char *filename, 441 | std::vector< std::vector > &points ) { 442 | irtkPointSet irtk_points; 443 | irtk_points.ReadVTK( filename ); 444 | for ( int i = 0; i < irtk_points.Size(); i++ ) { 445 | irtkPoint p; 446 | p = irtk_points(i); 447 | std::vector pt(3); 448 | pt[0] = p._x; pt[1] = p._y; pt[2] = p._z; 449 | points.push_back( pt ); 450 | } 451 | } 452 | 453 | void _write_points( char *filename, 454 | std::vector< std::vector > &points ) { 455 | irtkPointSet irtk_points; 456 | for ( int i = 0; i < irtk_points.Size(); i++ ) { 457 | irtk_points.Add( irtkPoint( points[i][0], 458 | points[i][1], 459 | points[i][2] ) ); 460 | } 461 | irtk_points.WriteVTK( filename ); 462 | } 463 | 464 | void _orientation( double* pixelSize, 465 | double* xAxis, 466 | double* yAxis, 467 | double* zAxis, 468 | double* origin, 469 | int* dim, 470 | int &i, int &j, int &k) { 471 | 472 | irtkGenericImage irtk_image; 473 | irtkImageAttributes attr; 474 | 475 | put_attributes( attr, 476 | pixelSize, 477 | xAxis, 478 | yAxis, 479 | zAxis, 480 | origin, 481 | dim ); 482 | 483 | irtk_image.Initialize(attr); 484 | 485 | irtk_image.Orientation( i, j, k ); 486 | } 487 | -------------------------------------------------------------------------------- /src/reconstruction.cc: -------------------------------------------------------------------------------- 1 | #include "reconstruction.h" 2 | 3 | void _reconstruct( 4 | // input stacks 5 | float* img, 6 | double* pixelSize, 7 | double* xAxis, 8 | double* yAxis, 9 | double* zAxis, 10 | double* origin, 11 | int* dim, 12 | 13 | // number of stacks 14 | int n, 15 | 16 | // stack ids: which stack each slice 17 | // comes from 18 | int* _stack_ids, 19 | 20 | // number of reconstruction iterations to run 21 | int iterations, 22 | 23 | // initial transformations 24 | double* tx, 25 | double* ty, 26 | double* tz, 27 | double* rx, 28 | double* ry, 29 | double* rz, 30 | 31 | // slice thickness 32 | double* _thickness, 33 | 34 | // mask (header same as template) 35 | float* mask_img, 36 | 37 | // output: reconstructed image 38 | float* reconstructed_img, 39 | double* reconstructed_pixelSize, 40 | double* reconstructed_xAxis, 41 | double* reconstructed_yAxis, 42 | double* reconstructed_zAxis, 43 | double* reconstructed_origin, 44 | int* reconstructed_dim ) { 45 | 46 | // /// Slices 47 | // std::vector< irtkGenericImage > slices; 48 | // pyList2irtkVector( slices, 49 | // img, 50 | // pixelSize, 51 | // xAxis, 52 | // yAxis, 53 | // zAxis, 54 | // origin, 55 | // dim, 56 | // n ); 57 | 58 | // /// Stack transformation 59 | // std::vector slice_transformations; 60 | // pyList2rigidVector( slice_transformations, 61 | // tx, ty, tz, 62 | // rx, ry, rz, 63 | // n ); 64 | 65 | // // convert thickness and stack_ids to std::vector 66 | // std::vector thickness(n); 67 | // std::vector stack_ids(n); 68 | // for ( int i = 0; i < n; i++ ) { 69 | // thickness[i] = _thickness[i]; 70 | // stack_ids[i] = _stack_ids[i]; 71 | // } 72 | 73 | // // template 74 | // irtkGenericImage reconstructed; 75 | // py2irtk( reconstructed, 76 | // reconstructed_img, 77 | // reconstructed_pixelSize, 78 | // reconstructed_xAxis, 79 | // reconstructed_yAxis, 80 | // reconstructed_zAxis, 81 | // reconstructed_origin, 82 | // reconstructed_dim ); 83 | 84 | // // mask 85 | // irtkGenericImage mask; 86 | // py2irtk( mask, 87 | // mask_img, 88 | // reconstructed_pixelSize, 89 | // reconstructed_xAxis, 90 | // reconstructed_yAxis, 91 | // reconstructed_zAxis, 92 | // reconstructed_origin, 93 | // reconstructed_dim ); 94 | 95 | // std::cout << "now creating reconstruction object\n"; 96 | 97 | // //Create reconstruction object 98 | // irtkReconstruction reconstruction; 99 | // int levels = 3; // Number of resolution levels 100 | // double sigma = 20; // Stdev for bias field 101 | // double lambda = 0.02; 102 | // double delta = 150; 103 | // double lastIterLambda = 0.01; 104 | // int rec_iterations; 105 | 106 | // //Set debug 107 | // reconstruction.DebugOn(); 108 | 109 | // //Set low intensity cutoff for bias estimation 110 | // reconstruction.SetLowIntensityCutoff(0.01); 111 | 112 | // //Set global bias correction flag 113 | // reconstruction.GlobalBiasCorrectionOff(); 114 | 115 | // //Rescale intensities of the stacks to have the same average 116 | // // reconstruction.MatchStackIntensities(stacks,stack_transformations,700); 117 | 118 | // reconstruction.SetSlicesAndTransformations( slices, 119 | // slice_transformations, 120 | // stack_ids, 121 | // thickness ); 122 | 123 | // std::cout << "slices have been read\n"; 124 | 125 | // reconstructed.Print(); 126 | 127 | // reconstruction.SetReconstructed( reconstructed ); 128 | 129 | // reconstruction.SetMask( &mask, 0 ); 130 | 131 | // std::cout << " ready to go...\n"; 132 | 133 | // //return; 134 | 135 | // // //Initialise data structures for EM 136 | // // reconstruction.InitializeEM(); 137 | 138 | // // //Calculate matrix of transformation between voxels of slices and volume 139 | // // reconstruction.CoeffInit(); 140 | 141 | // // //Initialize reconstructed image with Gaussian weighted reconstruction 142 | // // reconstruction.GaussianReconstruction(); 143 | 144 | // //Initialise data structures for EM 145 | // reconstruction.InitializeEM(); 146 | 147 | // // 148 | // // Interleaved registration-reconstruction iterations 149 | // // 150 | // for ( int iter = 0; iter < iterations; iter++ ) { 151 | // std::cout<<"Iteration "< 0 ) 156 | // reconstruction.SliceToVolumeRegistration(); // UPSAMPLING 157 | 158 | // //Set smoothing parameters 159 | // //amount of smoothing (given by lambda) is decreased with improving alignment 160 | // //delta (to determine edges) stays constant throughout 161 | // if ( iter == iterations-1 ) 162 | // reconstruction.SetSmoothingParameters(delta,lastIterLambda); 163 | // else { 164 | // double l = lambda; 165 | // for ( int i = 0; i < levels; i++ ) { 166 | // if ( iter == iterations*(levels-i-1)/levels ) 167 | // reconstruction.SetSmoothingParameters(delta, l); 168 | // l*=2; 169 | // } 170 | // } 171 | 172 | // //Use faster reconstruction during iterations and slower for final reconstruction 173 | // if ( iter < iterations-1 ) 174 | // reconstruction.SpeedupOn(); 175 | // else 176 | // reconstruction.SpeedupOff(); 177 | 178 | // //Initialise values of weights, scales and bias fields 179 | // reconstruction.InitializeEMValues(); 180 | 181 | // //Calculate matrix of transformation between voxels of slices and volume 182 | // reconstruction.CoeffInit(); 183 | 184 | // //Initialize reconstructed image with Gaussian weighted reconstruction 185 | // reconstruction.GaussianReconstruction(); 186 | 187 | // //Initialize robust statistics parameters 188 | // reconstruction.InitializeRobustStatistics(); 189 | 190 | // //EStep 191 | // reconstruction.EStep(); 192 | 193 | // //number of reconstruction iterations 194 | // if ( iter == iterations-1 ) 195 | // rec_iterations = 5; 196 | // else 197 | // rec_iterations = 3;//5; 198 | 199 | // //reconstruction iterations 200 | // for ( int i = 0; i < rec_iterations; i++ ) { 201 | // cout<0) 206 | // // reconstruction.Bias(); 207 | // // //calculate scales 208 | // // reconstruction.Scale(); 209 | // // } 210 | 211 | // //MStep and update reconstructed volume 212 | // reconstruction.Superresolution( i+1 ); 213 | // // if ( sigma > 0 ) 214 | // // reconstruction.NormaliseBias(i); 215 | 216 | // cout << "starting MStep\n"; 217 | // reconstruction.MStep(i+1); 218 | // cout << "finished MStep\n"; 219 | 220 | // //E-step 221 | // cout << "starting EStep\n"; 222 | // reconstruction.EStep(); 223 | // cout << "finished EStep\n"; 224 | 225 | // } //end of reconstruction iterations 226 | 227 | // // Mask reconstructed image to ROI given by the mask 228 | // // reconstruction.MaskVolume(); 229 | 230 | // }// end of interleaved registration-reconstruction iterations 231 | 232 | // // final result 233 | // //reconstruction.RestoreSliceIntensities(); 234 | // reconstruction.ScaleVolume(); 235 | // //reconstructed.Print(); 236 | 237 | // //irtkGenericImage reconstructed2; 238 | 239 | // reconstructed = reconstruction.GetReconstructed(); 240 | // //reconstructed.Write( "toto.nii"); 241 | 242 | // // reconstructed2.Print(); 243 | 244 | // irtk2py( reconstructed, 245 | // reconstructed_img, 246 | // reconstructed_pixelSize, 247 | // reconstructed_xAxis, 248 | // reconstructed_yAxis, 249 | // reconstructed_zAxis, 250 | // reconstructed_origin, 251 | // reconstructed_dim ); 252 | 253 | // reconstruction.GetTransformations( slice_transformations ); 254 | 255 | // rigidVector2pyList( slice_transformations, 256 | // tx, ty, tz, 257 | // rx, ry, rz ); 258 | 259 | } 260 | -------------------------------------------------------------------------------- /src/voxellise.cc: -------------------------------------------------------------------------------- 1 | #include "voxellise.h" 2 | 3 | #ifdef HAS_VTK 4 | 5 | void polydata_WorldToImage( vtkPolyData *poly, 6 | irtkGenericImage &image ) { 7 | double pt[3]; 8 | 9 | int noOfPts = poly->GetNumberOfPoints(); 10 | for (int i = 0; i < noOfPts; ++i){ 11 | poly->GetPoints()->GetPoint(i, pt); 12 | image.WorldToImage( pt[0], pt[1], pt[2] ); 13 | poly->GetPoints()->SetPoint(i, pt); 14 | } 15 | 16 | } 17 | 18 | void voxellise( vtkPolyData *poly, // input mesh (must be closed) 19 | irtkGenericImage &image, 20 | double value ) { 21 | 22 | vtkSmartPointer whiteImage = vtkSmartPointer::New(); 23 | double spacing[3]; 24 | spacing[0] = 1.0; 25 | spacing[1] = 1.0; 26 | spacing[2] = 1.0; 27 | whiteImage->SetSpacing(spacing); 28 | whiteImage->SetExtent( 0, image.GetX() - 1, 29 | 0, image.GetY() - 1, 30 | 0, image.GetZ() - 1 ); 31 | double origin[3]; 32 | origin[0] = 0; 33 | origin[1] = 0; 34 | origin[2] = 0; 35 | whiteImage->SetOrigin(origin); 36 | whiteImage->AllocateScalars(VTK_UNSIGNED_CHAR,1); 37 | 38 | for ( int i = 0; i < whiteImage->GetNumberOfPoints(); i++ ) 39 | whiteImage->GetPointData()->GetScalars()->SetTuple1(i, value); 40 | 41 | // polygonal data --> image stencil: 42 | vtkSmartPointer pol2stenc = 43 | vtkSmartPointer::New(); 44 | pol2stenc->SetInputData( poly ); 45 | pol2stenc->SetOutputOrigin(origin); 46 | pol2stenc->SetOutputSpacing(spacing); 47 | pol2stenc->SetTolerance(0.0); 48 | pol2stenc->SetOutputWholeExtent(whiteImage->GetExtent()); 49 | pol2stenc->Update(); 50 | 51 | // cut the corresponding white image and set the background: 52 | vtkSmartPointer imgstenc = 53 | vtkSmartPointer::New(); 54 | imgstenc->SetInputData(whiteImage); 55 | imgstenc->SetStencilData(pol2stenc->GetOutput()); 56 | imgstenc->ReverseStencilOff(); 57 | imgstenc->SetBackgroundValue(0); 58 | imgstenc->Update(); 59 | 60 | vtkSmartPointer vtkimageOut = 61 | vtkSmartPointer::New(); 62 | vtkimageOut = imgstenc->GetOutput(); 63 | vtkimageOut->Modified(); 64 | 65 | // Retrieve the output in IRTK 66 | int n = image.GetNumberOfVoxels(); 67 | uchar* ptr1 = image.GetPointerToVoxels(); 68 | uchar* ptr2 = (uchar*)vtkimageOut->GetScalarPointer(); 69 | for ( int i = 0; i < n; i++ ){ 70 | *ptr1 = *ptr2; 71 | ptr1++; 72 | ptr2++; 73 | } 74 | } 75 | 76 | void create_polydata( double* points, 77 | int npoints, 78 | int* triangles, 79 | int ntriangles, 80 | vtkPolyData *poly ) { 81 | 82 | int i; 83 | 84 | // Setup points 85 | vtkSmartPointer vtk_points = vtkSmartPointer::New(); 86 | for ( i = 0; i < npoints; i++ ) 87 | vtk_points->InsertNextPoint( points[index(i, 0, npoints, 3)], 88 | points[index(i, 1, npoints, 3)], 89 | points[index(i, 2, npoints, 3)] ); 90 | 91 | // Setup triangles 92 | vtkSmartPointer vtk_triangles = vtkSmartPointer::New(); 93 | for ( i = 0; i < ntriangles; i++ ) { 94 | vtkSmartPointer vtk_triangle = vtkSmartPointer::New(); 95 | vtk_triangle->GetPointIds()->SetId(0, triangles[index(i, 0, ntriangles, 3)]); 96 | vtk_triangle->GetPointIds()->SetId(1, triangles[index(i, 1, ntriangles, 3)]); 97 | vtk_triangle->GetPointIds()->SetId(2, triangles[index(i, 2, ntriangles, 3)]); 98 | vtk_triangles->InsertNextCell(vtk_triangle); 99 | } 100 | 101 | poly->SetPoints(vtk_points); 102 | poly->SetPolys(vtk_triangles); 103 | } 104 | 105 | 106 | 107 | #endif 108 | 109 | void _voxellise( double* points, 110 | int npoints, 111 | int* triangles, 112 | int ntriangles, 113 | uchar* img, 114 | double* pixelSize, 115 | double* xAxis, 116 | double* yAxis, 117 | double* zAxis, 118 | double* origin, 119 | int* dim ) { 120 | #ifdef HAS_VTK 121 | vtkSmartPointer poly = vtkSmartPointer::New(); 122 | 123 | create_polydata( points, 124 | npoints, 125 | triangles, 126 | ntriangles, 127 | poly ); 128 | 129 | 130 | 131 | // Write the file 132 | vtkSmartPointer writer = 133 | vtkSmartPointer::New(); 134 | writer->SetFileName("debug.vtk"); 135 | writer->SetInputData(poly); 136 | writer->Write(); 137 | 138 | irtkGenericImage irtk_image; 139 | py2irtk( irtk_image, 140 | img, 141 | pixelSize, 142 | xAxis, 143 | yAxis, 144 | zAxis, 145 | origin, 146 | dim ); 147 | 148 | polydata_WorldToImage( poly, irtk_image ); 149 | 150 | voxellise( poly, 151 | irtk_image, 152 | 1 ); 153 | 154 | irtk2py( irtk_image, 155 | img, 156 | pixelSize, 157 | xAxis, 158 | yAxis, 159 | zAxis, 160 | origin, 161 | dim ); 162 | #endif 163 | } 164 | 165 | void _shrinkDisk( uchar* img, 166 | int shape0, 167 | int shape1, 168 | double* center, 169 | double radius, 170 | int steps ) { 171 | 172 | #ifdef HAS_VTK 173 | 174 | //double pt[3]; 175 | 176 | vtkSmartPointer vtk_points = vtkSmartPointer::New(); 177 | vtkSmartPointer vtk_verts = vtkSmartPointer::New(); 178 | for ( int y = 0; y < shape0; y++ ) 179 | for ( int x = 0; x < shape1; x++ ) 180 | if ( img[index(y,x,shape0,shape1)] > 0 ) { 181 | // pt[0] = x; 182 | // pt[1] = y; 183 | // pt[3] = 0; 184 | //irtk_image.ImageToWorld( pt[0], pt[1], pt[2] ); 185 | vtk_verts->InsertNextCell(1); 186 | vtk_verts->InsertCellPoint( vtk_points->InsertNextPoint( x, 187 | y, 188 | 0 ) ); 189 | } 190 | //pt[0] = 0; 191 | //irtk_image.ImageToWorld( center[0], center[1], pt[0] ); 192 | vtkSmartPointer poly = vtkSmartPointer::New(); 193 | poly->SetPoints(vtk_points); 194 | poly->SetVerts(vtk_verts); 195 | 196 | // Create a circle 197 | vtkSmartPointer circle = 198 | vtkSmartPointer::New(); 199 | 200 | circle->GeneratePolygonOff(); 201 | circle->GeneratePolylineOn(); 202 | circle->SetNumberOfSides( steps ); 203 | circle->SetRadius( radius ); 204 | circle->SetCenter( center[1], center[0], 0 ); 205 | circle->Update(); 206 | 207 | vtkSmartPointer smoothFilter = 208 | vtkSmartPointer::New(); 209 | smoothFilter->SetInputConnection( circle->GetOutputPort() ); 210 | smoothFilter->SetSourceData( poly ); 211 | //smoothFilter->SetNumberOfIterations(10); 212 | smoothFilter->SetEdgeAngle( 180.0 ); 213 | smoothFilter->FeatureEdgeSmoothingOn(); 214 | smoothFilter->SetFeatureAngle(180.0); 215 | smoothFilter->Update(); 216 | std::cout << "edge angle " << smoothFilter->GetEdgeAngle()<<"\n"; 217 | 218 | // vtkSmartPointer writer = 219 | // vtkSmartPointer::New(); 220 | // writer->SetFileName("debug.vtk"); 221 | // writer->SetInput(circle->GetOutput()); 222 | // writer->Write(); 223 | 224 | irtkGenericImage irtk_image( shape1, shape0, 1 ); 225 | //irtk_image = 0; 226 | 227 | 228 | 229 | voxellise( //circle->GetOutput(), 230 | smoothFilter->GetOutput(), 231 | irtk_image, 232 | 1 ); 233 | 234 | irtk_image.Write( "irtk_image.nii"); 235 | 236 | irtk2py_buffer( irtk_image, img ); 237 | #endif 238 | } 239 | 240 | void _shrinkSphere( double* points, 241 | int npoints, 242 | uchar* img, 243 | double* pixelSize, 244 | double* xAxis, 245 | double* yAxis, 246 | double* zAxis, 247 | double* origin, 248 | int* dim ) { 249 | 250 | #ifdef HAS_VTK 251 | 252 | int i; 253 | double x, y, z; 254 | double cx, cy, cz; 255 | double r; 256 | double d; 257 | 258 | cx = 0; cy = 0; cz = 0; r = 0; 259 | 260 | // Setup points 261 | int id; 262 | vtkSmartPointer vtk_points = vtkSmartPointer::New(); 263 | vtkSmartPointer vtk_vertices = vtkSmartPointer::New(); 264 | for ( i = 0; i < npoints; i++ ) { 265 | x = points[index(i, 0, npoints, 3)]; 266 | y = points[index(i, 1, npoints, 3)]; 267 | z = points[index(i, 2, npoints, 3)]; 268 | id = vtk_points->InsertNextPoint( x, y, z ); 269 | vtk_vertices->InsertNextCell(1); 270 | vtk_vertices->InsertCellPoint(id); 271 | cx += x; 272 | cy += y; 273 | cz += z; 274 | } 275 | cx /= npoints; 276 | cy /= npoints; 277 | cz /= npoints; 278 | 279 | for ( i = 0; i < npoints; i++ ) { 280 | x = points[index(i, 0, npoints, 3)]; 281 | y = points[index(i, 1, npoints, 3)]; 282 | z = points[index(i, 2, npoints, 3)]; 283 | d = sqrt((x-cx)*(x-cx) + (y-cy)*(y-cy) + (z-cz)*(z-cz)); 284 | if (d>r) 285 | r = d; 286 | } 287 | 288 | vtkSmartPointer poly = vtkSmartPointer::New(); 289 | poly->SetPoints(vtk_points); 290 | poly->SetPolys(vtk_vertices); 291 | 292 | vtkSmartPointer sphere = 293 | vtkSmartPointer::New(); 294 | sphere->SetCenter(cx,cy,cz); 295 | sphere->SetRadius(r); 296 | sphere->SetPhiResolution(100); 297 | sphere->SetThetaResolution(100); 298 | 299 | vtkSmartPointer smoothFilter = 300 | vtkSmartPointer::New(); 301 | smoothFilter->SetInputConnection(0, sphere->GetOutputPort()); 302 | smoothFilter->SetInputData(1, poly); 303 | smoothFilter->Update(); 304 | 305 | poly = smoothFilter->GetOutput(); 306 | 307 | irtkGenericImage irtk_image; 308 | py2irtk( irtk_image, 309 | img, 310 | pixelSize, 311 | xAxis, 312 | yAxis, 313 | zAxis, 314 | origin, 315 | dim ); 316 | 317 | polydata_WorldToImage( poly, irtk_image ); 318 | 319 | voxellise( poly, 320 | irtk_image, 321 | 1 ); 322 | 323 | irtk2py( irtk_image, 324 | img, 325 | pixelSize, 326 | xAxis, 327 | yAxis, 328 | zAxis, 329 | origin, 330 | dim ); 331 | #endif 332 | } 333 | 334 | void _read_polydata( char* inputFilename, 335 | std::vector< std::vector >& points, 336 | std::vector< std::vector >& triangles ) { 337 | #ifdef HAS_VTK 338 | // Get all data from the file 339 | vtkSmartPointer reader = 340 | vtkSmartPointer::New(); 341 | reader->SetFileName(inputFilename); 342 | reader->Update(); 343 | 344 | // All of the standard data types can be checked and obtained like this: 345 | if(! reader->IsFilePolyData() ) { 346 | std::cout << "output is not a polydata" << std::endl; 347 | } 348 | vtkSmartPointer poly = reader->GetPolyDataOutput(); 349 | 350 | // http://www.vtk.org/pipermail/vtkusers/2007-September/042897.html 351 | for(vtkIdType i = 0; i < poly->GetNumberOfPoints(); i++) { 352 | double p[3]; 353 | poly->GetPoint(i,p); 354 | std::vector point(3); 355 | point[0] = p[0]; 356 | point[1] = p[1]; 357 | point[2] = p[2]; 358 | points.push_back(point); 359 | } 360 | 361 | vtkIdType npts, *pts; 362 | poly->GetPolys()->InitTraversal(); 363 | while ( poly->GetPolys()->GetNextCell(npts,pts) ) { 364 | std::vector triangle(3); 365 | triangle[0] = pts[0]; 366 | triangle[1] = pts[1]; 367 | triangle[2] = pts[2]; 368 | triangles.push_back(triangle); 369 | } 370 | 371 | return; 372 | 373 | #endif 374 | } 375 | --------------------------------------------------------------------------------