From b0e31aae3c080fc3cef1186427e59a307f6406d4 Mon Sep 17 00:00:00 2001 From: Daniel Ching Date: Tue, 22 Nov 2016 20:59:11 -0800 Subject: [PATCH 1/5] Fixing automatic version generation from git. --- setup.py | 8 ++---- version_hashtag.py | 70 ++++++++-------------------------------------- 2 files changed, 14 insertions(+), 64 deletions(-) diff --git a/setup.py b/setup.py index 3c30e0e..b9a4123 100755 --- a/setup.py +++ b/setup.py @@ -47,18 +47,16 @@ # ######################################################################### import setuptools -from version_hashtag import append_dev_info +from version_hashtag import retrieve_version_from_git -version_info = (0, 2, 0) -version = '.'.join([str(x) for x in version_info]) -version = append_dev_info(version) +version = retrieve_version_from_git() with open('VERSION', 'w') as f: f.write(version) setuptools.setup( name='xdesign', version=version, - author='Doga Gursoy', + author='Daniel Ching, Doga Gursoy', description='Benchmarking and optimization tools for tomography.', packages=setuptools.find_packages(exclude=['docs']), include_package_data=True, diff --git a/version_hashtag.py b/version_hashtag.py index 15ac76e..d2fbc0d 100644 --- a/version_hashtag.py +++ b/version_hashtag.py @@ -33,15 +33,12 @@ import os.path import subprocess -path_to_hashfile = os.path.join(os.path.dirname(__file__), "commit_hash.txt") - -def retrieve_git_info(): - """Prints the commit hash of HEAD to a file called 'commit_hash.txt'. - If the git command fails, it prints 'unknown-commit'. - If HEAD has tag with prefix "vM" where M is an integer, it prints an empty - str. Tags with such names are regarded as version or release tags. - Otherwise, it prints the commit hash as str. +def retrieve_version_from_git(): + """Returns a string. + If the git command fails, it returns 'unknown-commit'. + If HEAD has tag with prefix "vM" where M is an integer, it returns the tag. + If HEAD has any other tag, it returns "dev-" plus the tag. """ if os.path.exists('.git'): # Is Git installed? @@ -49,7 +46,8 @@ def retrieve_git_info(): subprocess.call(['git', '--version'], stdout=subprocess.PIPE) except OSError: - return None + return "unknown.commit" + # Decide whether this is a release p = subprocess.Popen( ['git', 'describe', '--tags', '--candidates=0', 'HEAD'], @@ -58,57 +56,11 @@ def retrieve_git_info(): p.wait() if p.returncode == 0: tag = p.stdout.read().decode('utf-8') + if tag.endswith('\n'): + tag = tag[:-1] if len(tag) >= 2 and tag.startswith('v'): try: int(tag[1]) - return 'release' + return tag[1:] except ValueError: - pass - # Otherwise, return commit hash - p = subprocess.Popen( - ['git', 'log', '-1', '--format=%H'], - stdout=subprocess.PIPE) - p.wait() - sha1 = p.stdout.read().decode('utf-8') - - # Provide commit hash or empty file to indicate release - if sha1 is None: - sha1 = 'unknown-commit' - elif sha1 == 'release': - sha1 = '' - commit_hash_header = ( - '# DO NOT EDIT! ' - 'This file was automatically generated by setup.py') - with open(path_to_hashfile, 'w') as f: - f.write(commit_hash_header + '\n') - f.write(sha1 + '\n') - - -def append_dev_info(version): - """Append annotation to version string to indicate development versions. An - empty (modulo comments and blank lines) commit_hash.txt is used to indicate - a release, in which case nothing is appended to version string as defined - above. - """ - retrieve_git_info() - - if os.path.exists(path_to_hashfile): - commit_hash = "" - with open(path_to_hashfile, "r") as f: - for line in f: - line = line.strip() - if len(line) == 0 or line[0] == '#': - # Ignore blank lines and comments, the latter being - # any line that begins with #. - continue - - # First non-blank line is assumed to be the commit hash - commit_hash = line - break - - if len(commit_hash) > 0: - version += ".dev0+" + commit_hash - else: - version += ".dev0+unknown.commit" - - return version + return 'dev-' + tag From a1eba6d3915a413a1e04d6af3e878986dea6116b Mon Sep 17 00:00:00 2001 From: Daniel Ching Date: Tue, 22 Nov 2016 21:24:01 -0800 Subject: [PATCH 2/5] Adding return statement to prevent returning none. Trying to make tags PEP440 compliant. --- version_hashtag.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/version_hashtag.py b/version_hashtag.py index d2fbc0d..39d180c 100644 --- a/version_hashtag.py +++ b/version_hashtag.py @@ -48,9 +48,9 @@ def retrieve_version_from_git(): except OSError: return "unknown.commit" - # Decide whether this is a release + # Get a tag from git. p = subprocess.Popen( - ['git', 'describe', '--tags', '--candidates=0', 'HEAD'], + ['git', 'describe', '--tags', 'HEAD'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) p.wait() @@ -59,8 +59,16 @@ def retrieve_version_from_git(): if tag.endswith('\n'): tag = tag[:-1] if len(tag) >= 2 and tag.startswith('v'): + # It's probably a version number try: int(tag[1]) - return tag[1:] except ValueError: - return 'dev-' + tag + return 'dev0+' + tag + # Get create a PEP440 compliant version number. + if tag.find('-') < 0: + return tag[1:] + else: + split = tag.find('-') + return tag[1:split] + '+dev' + tag[split+1:].replace('-','.') + + return "unknown.commit" From 0c078a55083f6e6e2067fee60e2d955f2b34681e Mon Sep 17 00:00:00 2001 From: Daniel Ching Date: Thu, 24 Nov 2016 15:31:30 -0800 Subject: [PATCH 3/5] Editing and adding things to the documentation. --- docs/source/api/xdesign.acquisition.rst | 5 +- docs/source/api/xdesign.algorithms.rst | 5 +- docs/source/api/xdesign.feature.rst | 5 +- docs/source/api/xdesign.geometry.rst | 8 ++- docs/source/api/xdesign.material.rst | 5 +- docs/source/api/xdesign.metrics.rst | 5 +- docs/source/api/xdesign.phantom.rst | 5 +- docs/source/api/xdesign.plot.rst | 17 ++++- docs/source/bibtex/refs.bib | 36 ++++++++--- docs/source/conf.py | 7 +-- docs/source/index.rst | 8 +-- docs/source/{refs.rst => zrefs.rst} | 2 +- xdesign/feature.py | 39 ++++++------ xdesign/geometry.py | 6 +- xdesign/metrics.py | 32 +++------- xdesign/phantom.py | 50 ++++++++------- xdesign/plot.py | 83 +++++++++++++++++-------- 17 files changed, 195 insertions(+), 123 deletions(-) rename docs/source/{refs.rst => zrefs.rst} (88%) diff --git a/docs/source/api/xdesign.acquisition.rst b/docs/source/api/xdesign.acquisition.rst index 52d5e74..0665dae 100644 --- a/docs/source/api/xdesign.acquisition.rst +++ b/docs/source/api/xdesign.acquisition.rst @@ -5,12 +5,15 @@ :members: :show-inheritance: :undoc-members: + :synopsis: Defines objects related to collection and organization of probe data. .. rubric:: **Functions:** .. autosummary:: - + Beam Probe sinogram angleogram + +.. moduleauthor:: Doga Gursoy diff --git a/docs/source/api/xdesign.algorithms.rst b/docs/source/api/xdesign.algorithms.rst index 1c21da5..2e5b807 100644 --- a/docs/source/api/xdesign.algorithms.rst +++ b/docs/source/api/xdesign.algorithms.rst @@ -5,13 +5,16 @@ :members: :show-inheritance: :undoc-members: + :synopsis: Defines methods for reconstructing data from the :mod:`.acquisition` module. .. rubric:: **Functions:** .. autosummary:: - + reconstruct art sirt mlem stream + +.. moduleauthor:: Doga Gursoy diff --git a/docs/source/api/xdesign.feature.rst b/docs/source/api/xdesign.feature.rst index 14ebd57..dd7d686 100644 --- a/docs/source/api/xdesign.feature.rst +++ b/docs/source/api/xdesign.feature.rst @@ -5,9 +5,12 @@ :members: :show-inheritance: :undoc-members: + :synopsis: Defines an object for spatial organizing materials properties. .. rubric:: **Functions:** .. autosummary:: - + Feature + +.. moduleauthor:: Daniel J Ching diff --git a/docs/source/api/xdesign.geometry.rst b/docs/source/api/xdesign.geometry.rst index 8f4373d..8d547c7 100644 --- a/docs/source/api/xdesign.geometry.rst +++ b/docs/source/api/xdesign.geometry.rst @@ -5,18 +5,20 @@ :members: :show-inheritance: :undoc-members: + :synopsis: Defines geometric objects for the purpose of supporting :class:`.Feature` definition and calculating intersections for the :mod:`.acquisition` module. .. rubric:: **Functions:** .. autosummary:: - + Point Superellipse Ellipse Circle Line - Segment - Ray Triangle Rectangle Square + +.. moduleauthor:: Doga Gursoy +.. moduleauthor:: Daniel J Ching diff --git a/docs/source/api/xdesign.material.rst b/docs/source/api/xdesign.material.rst index b0f2d5f..0dcdd18 100644 --- a/docs/source/api/xdesign.material.rst +++ b/docs/source/api/xdesign.material.rst @@ -5,11 +5,12 @@ :members: :show-inheritance: :undoc-members: + :synopsis: Defines objects which auto-generate a parameterized :class:`.Phantom`. .. rubric:: **Functions:** .. autosummary:: - + Material HyperbolicConcentric DynamicRange @@ -17,3 +18,5 @@ Soil Foam Electronics + +.. moduleauthor:: Daniel J Ching diff --git a/docs/source/api/xdesign.metrics.rst b/docs/source/api/xdesign.metrics.rst index 2dd21d0..1944a3e 100644 --- a/docs/source/api/xdesign.metrics.rst +++ b/docs/source/api/xdesign.metrics.rst @@ -5,11 +5,12 @@ :members: :show-inheritance: :undoc-members: + :synopsis: Objects and methods for computing the quality of reconstructions. .. rubric:: **Functions:** .. autosummary:: - + ImageQuality probability_mask compute_quality @@ -19,3 +20,5 @@ compute_mtf compute_nps compute_neq + +.. moduleauthor:: Daniel J Ching diff --git a/docs/source/api/xdesign.phantom.rst b/docs/source/api/xdesign.phantom.rst index aeed302..734a476 100644 --- a/docs/source/api/xdesign.phantom.rst +++ b/docs/source/api/xdesign.phantom.rst @@ -5,9 +5,12 @@ :members: :show-inheritance: :undoc-members: + :synopsis: Defines an object for organizing :class:`.Feature`. .. rubric:: **Functions:** .. autosummary:: - + Phantom + +.. moduleauthor:: Daniel J Ching diff --git a/docs/source/api/xdesign.plot.rst b/docs/source/api/xdesign.plot.rst index b700e19..6cc5879 100644 --- a/docs/source/api/xdesign.plot.rst +++ b/docs/source/api/xdesign.plot.rst @@ -1,15 +1,26 @@ :mod:`xdesign.plot` -=================== +==================== .. automodule:: xdesign.plot :members: :show-inheritance: :undoc-members: + :synopsis: Contains functions for visualizing :class:`.Phantom` and :class:`.ImageQuality` metrics. .. rubric:: **Functions:** .. autosummary:: - + + sidebyside + discrete_phantom plot_phantom + plot_feature + plot_mesh + plot_polygon + plot_curve plot_metrics - plot_histograms + plot_mtf + plot_nps + plot_neq + +.. moduleauthor:: Daniel J Ching diff --git a/docs/source/bibtex/refs.bib b/docs/source/bibtex/refs.bib index b5df340..f549849 100644 --- a/docs/source/bibtex/refs.bib +++ b/docs/source/bibtex/refs.bib @@ -41,7 +41,7 @@ @article{Sufian:15 @article{Bergamaschi:fv5047, author = "Bergamaschi, Antoine and Medjoubi, Kadda and Messaoudi, C{\'{e}}dric and Marco, Sergio and Somogyi, Andrea", title = "{{\it MMX-I}: data-processing software for multimodal X-ray imaging and tomography}", journal = "Journal of Synchrotron Radiation", year = "2016", volume = "23", number = "3", pages = "783--794", month = "May", doi = {10.1107/S1600577516003052}, url = {http://dx.doi.org/10.1107/S1600577516003052}, abstract = {A new multi-platform freeware has been developed for the processing and reconstruction of scanning multi-technique X-ray imaging and tomography datasets. The software platform aims to treat different scanning imaging techniques: X-ray fluorescence, phase, absorption and dark field and any of their combinations, thus providing an easy-to-use data processing tool for the X-ray imaging user community. A dedicated data input stream copes with the input and management of large datasets (several hundred GB) collected during a typical multi-technique fast scan at the Nanoscopium beamline and even on a standard PC. To the authors' knowledge, this is the first software tool that aims at treating all of the modalities of scanning multi-technique imaging and tomography experiments.}, keywords = {scanning multimodal X-ray imaging, scanning X-ray tomography, tomographic reconstruction, phase retrieval, scanning multimodal X-ray imaging, scanning X-ray tomography, tomographic reconstruction, phase retrieval}, } -@article{Hsieh:06, author = "Hsieh, Jiang and Londt, John and Vass, Melissa and Li, Jay and Tang, Xiangyang and Okerlund, Darin", title = "Step-and-shoot data acquisition and reconstruction for cardiac x-ray computed tomography", journal = "Medical Physics", year = "2006", volume = "33", number = "11", pages = "4236-4248", url = "http://scitation.aip.org/content/aapm/journal/medphys/33/11/10.1118/1.2361078", doi = "http://dx.doi.org/10.1118/1.2361078" } +@article{Hsieh:06, author = "Hsieh, Jiang and Londt, John and Vass, Melissa and Li, Jay and Tang, Xiangyang and Okerlund, Darin", title = "Step-and-shoot data acquisition and reconstruction for cardiac x-ray computed tomography", journal = "Medical Physics", year = "2006", volume = "33", number = "11", pages = "4236-4248", url = "http://scitation.aip.org/content/aapm/journal/medphys/33/11/10.1118/1.2361078", doi = "http://dx.doi.org/10.1118/1.2361078" } @article{Beverley:16, author={Beverley F Holman and Vesna Cuplov and Brian F Hutton and Ashley M Groves and Kris Thielemans}, title={The effect of respiratory induced density variations on non-TOF PET quantitation in the lung}, journal={Physics in Medicine and Biology}, volume={61}, number={8}, pages={3148}, url={http://stacks.iop.org/0031-9155/61/i=8/a=3148}, year={2016} } @@ -53,30 +53,30 @@ @article{Marchesini:16 @article{Agostinelli:01, title = "An object oriented fully 3D tomography visual toolkit ", journal = "Computer Methods and Programs in Biomedicine ", volume = "65", number = "1", pages = "61 - 69", year = "2001", note = "", issn = "0169-2607", doi = "http://dx.doi.org/10.1016/S0169-2607(00)00101-2", url = "http://www.sciencedirect.com/science/article/pii/S0169260700001012", author = "Stefano Agostinelli and Gabriella Paoli", keywords = "Object oriented", keywords = "Fully 3D", keywords = "Tomography visual toolkit ", abstract = "In this paper we present a modern object oriented component object model (COMM) C + + toolkit dedicated to fully 3D cone-beam tomography. The toolkit allows the display and visual manipulation of analytical phantoms, projection sets and volumetric data through a standard Windows graphical user interface. Data input/output is performed using proprietary file formats but import/export of industry standard file formats, including raw binary, Windows bitmap and AVI, ACR/NEMA \{DICOMM\} 3 and \{NCSA\} \{HDF\} is available. At the time of writing built-in implemented data manipulators include a basic phantom ray-tracer and a Matrox Genesis frame grabbing facility. A \{COMM\} plug-in interface is provided for user-defined custom backprojector algorithms: a simple Feldkamp ActiveX control, including source code, is provided as an example; our fast Feldkamp plug-in is also available. " } -@article{Bayford:95, author={R Bayford and Y Hanquan and K Boone and D S Holder}, title={Experimental validation of a novel reconstruction algorithm for electrical impedance tomography based on backprojection of Lagrange multipliers}, journal={Physiological Measurement}, volume={16}, number={3A}, pages={A237}, url={http://stacks.iop.org/0967-3334/16/i=3A/a=022}, year={1995}, abstract={A novel approach to image reconstruction for electrical impedance tomography (EIT) has been developed. It is based on a constrained optimization technique for the reconstruction of difference resistivity images without finite-element modelling. It solves the inverse problem by optimizing a cost function under constraints, in the form of normalized boundary potentials. Its application to the neighbouring data collection method is presented here. Mathematical models are developed according to specified criteria. These express the reconstructed image in terms of one-dimensional Lagrange multiplier functions. The reconstruction problem becomes one of estimating these functions from normalized boundary potentials. This model is based on a cost criterion of the minimization of the variance between the reconstructed and the true resistivity distributions. The algorithm was tested on data collected in a cylindrical saline-filled tank. A polyacrylamide rod was placed in various positions with or without a peripheral plaster of Paris ring in place. This was intended to resemble the conditions during EIT of epileptic seizures recorded with scalp or cortical electrodes in the human head. One advantage of this approach is that compensation for non-uniform initial conditions may be made, as this is a significant problem in imaging cerebral activity through the skull.} } @article{Chaâri:11, title = "A wavelet-based regularized reconstruction algorithm for \{SENSE\} parallel \{MRI\} with applications to neuroimaging ", journal = "Medical Image Analysis ", volume = "15", number = "2", pages = "185 - 201", year = "2011", note = "", issn = "1361-8415", doi = "http://dx.doi.org/10.1016/j.media.2010.08.001", url = "http://www.sciencedirect.com/science/article/pii/S1361841510001052", author = "Lotfi Chaâri and Jean-Christophe Pesquet and Amel Benazza-Benyahia and Philippe Ciuciu", keywords = "Parallel MRI", keywords = "SENSE reconstruction", keywords = "Regularization", keywords = "Wavelet transform", keywords = "Convex optimization ", abstract = "To reduce scanning time and/or improve spatial/temporal resolution in some Magnetic Resonance Imaging (MRI) applications, parallel \{MRI\} acquisition techniques with multiple coils acquisition have emerged since the early 1990s as powerful imaging methods that allow a faster acquisition process. In these techniques, the full \{FOV\} image has to be reconstructed from the resulting acquired undersampled k-space data. To this end, several reconstruction techniques have been proposed such as the widely-used \{SENSitivity\} Encoding (SENSE) method. However, the reconstructed image generally presents artifacts when perturbations occur in both the measured data and the estimated coil sensitivity profiles. In this paper, we aim at achieving accurate image reconstruction under degraded experimental conditions (low magnetic field and high reduction factor), in which neither the \{SENSE\} method nor the Tikhonov regularization in the image domain give convincing results. To this end, we present a novel method for SENSE-based reconstruction which proceeds with regularization in the complex wavelet domain by promoting sparsity. The proposed approach relies on a fast algorithm that enables the minimization of regularized non-differentiable criteria including more general penalties than a classical ℓ1 term. To further enhance the reconstructed image quality, local convex constraints are added to the regularization process. In vivo human brain experiments carried out on Gradient-Echo (GRE) anatomical and Echo Planar Imaging (EPI) functional \{MRI\} data at 1.5 T indicate that our algorithm provides reconstructed images with reduced artifacts for high reduction factors. " } +@article{Bayford:95, author={R Bayford and Y Hanquan and K Boone and D S Holder}, title={Experimental validation of a novel reconstruction algorithm for electrical impedance tomography based on backprojection of Lagrange multipliers}, journal={Physiological Measurement}, volume={16}, number={3A}, pages={A237}, url={http://stacks.iop.org/0967-3334/16/i=3A/a=022}, year={1995}, abstract={A novel approach to image reconstruction for electrical impedance tomography (EIT) has been developed. It is based on a constrained optimization technique for the reconstruction of difference resistivity images without finite-element modelling. It solves the inverse problem by optimizing a cost function under constraints, in the form of normalized boundary potentials. Its application to the neighbouring data collection method is presented here. Mathematical models are developed according to specified criteria. These express the reconstructed image in terms of one-dimensional Lagrange multiplier functions. The reconstruction problem becomes one of estimating these functions from normalized boundary potentials. This model is based on a cost criterion of the minimization of the variance between the reconstructed and the true resistivity distributions. The algorithm was tested on data collected in a cylindrical saline-filled tank. A polyacrylamide rod was placed in various positions with or without a peripheral plaster of Paris ring in place. This was intended to resemble the conditions during EIT of epileptic seizures recorded with scalp or cortical electrodes in the human head. One advantage of this approach is that compensation for non-uniform initial conditions may be made, as this is a significant problem in imaging cerebral activity through the skull.} } @article{Chaâri:11, title = "A wavelet-based regularized reconstruction algorithm for \{SENSE\} parallel \{MRI\} with applications to neuroimaging ", journal = "Medical Image Analysis ", volume = "15", number = "2", pages = "185 - 201", year = "2011", note = "", issn = "1361-8415", doi = "http://dx.doi.org/10.1016/j.media.2010.08.001", url = "http://www.sciencedirect.com/science/article/pii/S1361841510001052", author = "Lotfi Chaâri and Jean-Christophe Pesquet and Amel Benazza-Benyahia and Philippe Ciuciu", keywords = "Parallel MRI", keywords = "SENSE reconstruction", keywords = "Regularization", keywords = "Wavelet transform", keywords = "Convex optimization ", abstract = "To reduce scanning time and/or improve spatial/temporal resolution in some Magnetic Resonance Imaging (MRI) applications, parallel \{MRI\} acquisition techniques with multiple coils acquisition have emerged since the early 1990s as powerful imaging methods that allow a faster acquisition process. In these techniques, the full \{FOV\} image has to be reconstructed from the resulting acquired undersampled k-space data. To this end, several reconstruction techniques have been proposed such as the widely-used \{SENSitivity\} Encoding (SENSE) method. However, the reconstructed image generally presents artifacts when perturbations occur in both the measured data and the estimated coil sensitivity profiles. In this paper, we aim at achieving accurate image reconstruction under degraded experimental conditions (low magnetic field and high reduction factor), in which neither the \{SENSE\} method nor the Tikhonov regularization in the image domain give convincing results. To this end, we present a novel method for SENSE-based reconstruction which proceeds with regularization in the complex wavelet domain by promoting sparsity. The proposed approach relies on a fast algorithm that enables the minimization of regularized non-differentiable criteria including more general penalties than a classical ℓ1 term. To further enhance the reconstructed image quality, local convex constraints are added to the regularization process. In vivo human brain experiments carried out on Gradient-Echo (GRE) anatomical and Echo Planar Imaging (EPI) functional \{MRI\} data at 1.5 T indicate that our algorithm provides reconstructed images with reduced artifacts for high reduction factors. " } @ARTICLE{Dean-Ben:12, author={X. L. Dean-Ben and A. Buehler and V. Ntziachristos and D. Razansky}, journal={IEEE Transactions on Medical Imaging}, title={Accurate Model-Based Reconstruction Algorithm for Three-Dimensional Optoacoustic Tomography}, year={2012}, volume={31}, number={10}, pages={1922-1928}, keywords={acoustic tomography;biomedical ultrasonics;image reconstruction;image resolution;medical image processing;optical tomography;phantoms;1D scanning geometry;3D optoacoustic tomography;backprojection inversion algorithm;dimensionality;image contrast loss;image reconstruction;image spatial resolution;imaging speed;model based reconstruction algorithm;out-of-plane image artifacts;phantom;Absorption;Computational modeling;Image reconstruction;Phantoms;Tomography;Transducers;Model-based reconstruction;optoacoustic tomography;photoacoustic tomography;three-dimensional imaging;Algorithms;Animals;Computer Simulation;Heart;Imaging, Three-Dimensional;Mice;Models, Theoretical;Phantoms, Imaging;Photoacoustic Techniques;Tomography}, doi={10.1109/TMI.2012.2208471}, ISSN={0278-0062}, month={Oct},} -@article{Dobbins:95, author = "Dobbins, James T.", title = "Effects of undersampling on the proper interpretation of modulation transfer function, noise power spectra, and noise equivalent quanta of digital imaging systems", journal = "Medical Physics", year = "1995", volume = "22", number = "2", pages = "171-181", url = "http://scitation.aip.org/content/aapm/journal/medphys/22/2/10.1118/1.597600", doi = "http://dx.doi.org/10.1118/1.597600" } +@article{Dobbins:95, author = "Dobbins, James T.", title = "Effects of undersampling on the proper interpretation of modulation transfer function, noise power spectra, and noise equivalent quanta of digital imaging systems", journal = "Medical Physics", year = "1995", volume = "22", number = "2", pages = "171-181", url = "http://scitation.aip.org/content/aapm/journal/medphys/22/2/10.1118/1.597600", doi = "http://dx.doi.org/10.1118/1.597600" } -@article{Friedman:13, author = "Friedman, Saul N. and Fung, George S. K. and Siewerdsen, Jeffrey H. and Tsui, Benjamin M. W.", title = "A simple approach to measure computed tomography (CT) modulation transfer function (MTF) and noise-power spectrum (NPS) using the American College of Radiology (ACR) accreditation phantom", journal = "Medical Physics", year = "2013", volume = "40", number = "5", eid = 051907, pages = "", url = "http://scitation.aip.org/content/aapm/journal/medphys/40/5/10.1118/1.4800795", doi = "http://dx.doi.org/10.1118/1.4800795" } +@article{Friedman:13, author = "Friedman, Saul N. and Fung, George S. K. and Siewerdsen, Jeffrey H. and Tsui, Benjamin M. W.", title = "A simple approach to measure computed tomography (CT) modulation transfer function (MTF) and noise-power spectrum (NPS) using the American College of Radiology (ACR) accreditation phantom", journal = "Medical Physics", year = "2013", volume = "40", number = "5", eid = 051907, pages = "", url = "http://scitation.aip.org/content/aapm/journal/medphys/40/5/10.1118/1.4800795", doi = "http://dx.doi.org/10.1118/1.4800795" } @article{Han:12, author = "B. Kelly Han and Katharine L.R. Grant and Ross Garberich and Martin Sedlmair and Jana Lindberg and John R. Lesser", title = "Assessment of an iterative reconstruction algorithm (SAFIRE) on image quality in pediatric cardiac \{CT\} datasets ", journal = "Journal of Cardiovascular Computed Tomography ", volume = "6", number = "3", pages = "200 - 204", year = "2012", note = "", issn = "1934-5925", doi = "http://dx.doi.org/10.1016/j.jcct.2012.04.008", url = "http://www.sciencedirect.com/science/article/pii/S1934592512001402", } -@article{Hsieh:04, author = "Hsieh, J. and Chao, E. and Thibault, J. and Grekowicz, B. and Horst, A. and McOlash, S. and Myers, T. J.", title = "A novel reconstruction algorithm to extend the CT scan field-of-view", journal = "Medical Physics", year = "2004", volume = "31", number = "9", pages = "2385-2391", url = "http://scitation.aip.org/content/aapm/journal/medphys/31/9/10.1118/1.1776673", doi = "http://dx.doi.org/10.1118/1.1776673" } @Article{Hunter:07, Author = {Hunter, J. D.}, Title = {Matplotlib: A 2D graphics environment}, Journal = {Computing In Science \& Engineering}, Volume = {9}, Number = {3}, Pages = {90--95}, abstract = {Matplotlib is a 2D graphics package used for Python for application development, interactive scripting, and publication-quality image generation across user interfaces and operating systems.}, publisher = {IEEE COMPUTER SOC}, year = 2007 } +@article{Hsieh:04, author = "Hsieh, J. and Chao, E. and Thibault, J. and Grekowicz, B. and Horst, A. and McOlash, S. and Myers, T. J.", title = "A novel reconstruction algorithm to extend the CT scan field-of-view", journal = "Medical Physics", year = "2004", volume = "31", number = "9", pages = "2385-2391", url = "http://scitation.aip.org/content/aapm/journal/medphys/31/9/10.1118/1.1776673", doi = "http://dx.doi.org/10.1118/1.1776673" } @Article{Hunter:07, Author = {Hunter, J. D.}, Title = {Matplotlib: A 2D graphics environment}, Journal = {Computing In Science \& Engineering}, Volume = {9}, Number = {3}, Pages = {90--95}, abstract = {Matplotlib is a 2D graphics package used for Python for application development, interactive scripting, and publication-quality image generation across user interfaces and operating systems.}, publisher = {IEEE COMPUTER SOC}, year = 2007 } @article{Jan:04, author={S Jan and G Santin and D Strul and S Staelens and K Assié and D Autret and S Avner and R Barbier and M Bardiès and P M Bloomfield and D Brasse and V Breton and P Bruyndonckx and I Buvat and A F Chatziioannou and Y Choi and Y H Chung and C Comtat and D Donnarieix and L Ferrer and S J Glick and C J Groiselle and D Guez and P-F Honore and S Kerhoas-Cavata and A S Kirov and V Kohli and M Koole and M Krieguer and D J van der Laan and F Lamare and G Largeron and C Lartizien and D Lazaro and M C Maas and L Maigne and F Mayet and F Melot and C Merheb and E Pennacchio and J Perez and U Pietrzyk and F R Rannou and M Rey and D R Schaart and C R Schmidtlein and L Simon and T Y Song and J-M Vieira and D Visvikis and R Van de Walle and E Wieërs and C Morel}, title={GATE: a simulation toolkit for PET and SPECT}, journal={Physics in Medicine and Biology}, volume={49}, number={19}, pages={4543}, url={http://stacks.iop.org/0031-9155/49/i=19/a=007}, year={2004}, abstract={Monte Carlo simulation is an essential tool in emission tomography that can assist in the design of new medical imaging devices, the optimization of acquisition protocols and the development or assessment of image reconstruction algorithms and correction techniques. GATE, the Geant4 Application for Tomographic Emission, encapsulates the Geant4 libraries to achieve a modular, versatile, scripted simulation toolkit adapted to the field of nuclear medicine. In particular, GATE allows the description of time-dependent phenomena such as source or detector movement, and source decay kinetics. This feature makes it possible to simulate time curves under realistic acquisition conditions and to test dynamic reconstruction algorithms. This paper gives a detailed description of the design and development of GATE by the OpenGATE collaboration, whose continuing objective is to improve, document and validate GATE by simulating commercially available imaging systems for PET and SPECT. Large effort is also invested in the ability and the flexibility to model novel detection systems or systems still under design. A public release of GATE licensed under the GNU Lesser General Public License can be downloaded at http://www-lphe.epfl.ch/GATE/ [http://www-lphe.epfl.ch/GATE/] . Two benchmarks developed for PET and SPECT to test the installation of GATE and to serve as a tutorial for the users are presented. Extensive validation of the GATE simulation platform has been started, comparing simulations and measurements on commercially available acquisition systems. References to those results are listed. The future prospects towards the gridification of GATE and its extension to other domains such as dosimetry are also discussed.} } @ARTICLE{Kostli:01, author={K. P. Kostli and D. Frauchiger and J. J. Niederhauser and G. Paltauf and H. P. Weber and M. Frenz}, journal={IEEE Journal of Selected Topics in Quantum Electronics}, title={Optoacoustic imaging using a three-dimensional reconstruction algorithm}, year={2001}, volume={7}, number={6}, pages={918-923}, keywords={acoustic tomography;biomedical ultrasonics;fast Fourier transforms;image reconstruction;inverse problems;medical image processing;photoacoustic effect;2-D pressure distributions;3-D optoacoustic images;Fourier-reconstruction algorithm;Green's function;Poisson integral;backprojection;blood vessel model;decomposition into plane waves;fast Fourier algorithm;forward problem;four-dimensional space-time;gated CCD camera;insect body;intensity changes;inverse problem;medical diagnostics;optical pressure transducer;optoacoustic imaging;reflected probe beam;sample surface;simulated pressure transients;three-dimensional reconstruction algorithm;tomography images;Delay;Distributed computing;Image reconstruction;Image resolution;Laser excitation;Optical pulses;Pressure measurement;Pulse measurements;Surface reconstruction;Two dimensional displays}, doi={10.1109/2944.983294}, ISSN={1077-260X}, month={Nov},} -@article{Köhler:11, author = "Köhler, Thomas and Brendel, Bernhard and Roessl, Ewald", title = "Iterative reconstruction for differential phase contrast imaging using spherically symmetric basis functions", journal = "Medical Physics", year = "2011", volume = "38", number = "8", pages = "4542-4545", url = "http://scitation.aip.org/content/aapm/journal/medphys/38/8/10.1118/1.3608906", doi = "http://dx.doi.org/10.1118/1.3608906" } @article{Kumar:15, author = "Kumar, Arjun S. and Mandal, Pratiti and Zhang, Yongjie and Litster, Shawn", title = "Image segmentation of nanoscale Zernike phase contrast X-ray computed tomography images", journal = "Journal of Applied Physics", year = "2015", volume = "117", number = "18", eid = 183102, pages = "", url = "http://scitation.aip.org/content/aip/journal/jap/117/18/10.1063/1.4919835", doi = "http://dx.doi.org/10.1063/1.4919835" } @article{Marone:12, author = "Marone, F. and Stampanoni, M.", title = "{Regridding reconstruction algorithm for real-time tomographic imaging}", journal = "Journal of Synchrotron Radiation", year = "2012", volume = "19", number = "6", pages = "1029--1037", month = "Nov", doi = {10.1107/S0909049512032864}, url = {http://dx.doi.org/10.1107/S0909049512032864}, abstract = {Sub-second temporal-resolution tomographic microscopy is becoming a reality at third-generation synchrotron sources. Efficient data handling and post-processing is, however, difficult when the data rates are close to 10GBs${\sp {$-$}1}$. This bottleneck still hinders exploitation of the full potential inherent in the ultrafast acquisition speed. In this paper the fast reconstruction algorithm {\it gridrec}, highly optimized for conventional CPU technology, is presented. It is shown that {\it gridrec} is a valuable alternative to standard filtered back-projection routines, despite being based on the Fourier transform method. In fact, the regridding procedure used for resampling the Fourier space from polar to Cartesian coordinates couples excellent performance with negligible accuracy degradation. The stronger dependence of the observed signal-to-noise ratio for {\it gridrec} reconstructions on the number of angular views makes the presented algorithm even superior to filtered back-projection when the tomographic problem is well sampled. {\it Gridrec} not only guarantees high-quality results but it provides up to 20-fold performance increase, making real-time monitoring of the sub-second acquisition process a reality.}, keywords = {tomographic reconstruction, fast algorithm, Fourier method, regridding, PSWF}, } +@article{Köhler:11, author = "Köhler, Thomas and Brendel, Bernhard and Roessl, Ewald", title = "Iterative reconstruction for differential phase contrast imaging using spherically symmetric basis functions", journal = "Medical Physics", year = "2011", volume = "38", number = "8", pages = "4542-4545", url = "http://scitation.aip.org/content/aapm/journal/medphys/38/8/10.1118/1.3608906", doi = "http://dx.doi.org/10.1118/1.3608906" } @article{Kumar:15, author = "Kumar, Arjun S. and Mandal, Pratiti and Zhang, Yongjie and Litster, Shawn", title = "Image segmentation of nanoscale Zernike phase contrast X-ray computed tomography images", journal = "Journal of Applied Physics", year = "2015", volume = "117", number = "18", eid = 183102, pages = "", url = "http://scitation.aip.org/content/aip/journal/jap/117/18/10.1063/1.4919835", doi = "http://dx.doi.org/10.1063/1.4919835" } @article{Marone:12, author = "Marone, F. and Stampanoni, M.", title = "{Regridding reconstruction algorithm for real-time tomographic imaging}", journal = "Journal of Synchrotron Radiation", year = "2012", volume = "19", number = "6", pages = "1029--1037", month = "Nov", doi = {10.1107/S0909049512032864}, url = {http://dx.doi.org/10.1107/S0909049512032864}, abstract = {Sub-second temporal-resolution tomographic microscopy is becoming a reality at third-generation synchrotron sources. Efficient data handling and post-processing is, however, difficult when the data rates are close to 10GBs${\sp {$-$}1}$. This bottleneck still hinders exploitation of the full potential inherent in the ultrafast acquisition speed. In this paper the fast reconstruction algorithm {\it gridrec}, highly optimized for conventional CPU technology, is presented. It is shown that {\it gridrec} is a valuable alternative to standard filtered back-projection routines, despite being based on the Fourier transform method. In fact, the regridding procedure used for resampling the Fourier space from polar to Cartesian coordinates couples excellent performance with negligible accuracy degradation. The stronger dependence of the observed signal-to-noise ratio for {\it gridrec} reconstructions on the number of angular views makes the presented algorithm even superior to filtered back-projection when the tomographic problem is well sampled. {\it Gridrec} not only guarantees high-quality results but it provides up to 20-fold performance increase, making real-time monitoring of the sub-second acquisition process a reality.}, keywords = {tomographic reconstruction, fast algorithm, Fourier method, regridding, PSWF}, } @inproceedings{palenstijn:13, title={The ASTRA tomography toolbox}, author={Palenstijn, Willem Jan and Batenburg, K Joost and Sijbers, Jan}, booktitle={13th International Conference on Computational and Mathematical Methods in Science and Engineering, CMMSE}, volume={2013}, year={2013} } @article{roy:05, title={Tomographic fluorescence imaging in tissue phantoms: a novel reconstruction algorithm and imaging geometry}, author={Roy, Ranadhir and Thompson, Alan B and Godavarty, Anuradha and Sevick-Muraca, Eva M}, journal={IEEE transactions on medical imaging}, volume={24}, number={2}, pages={137--154}, year={2005}, publisher={IEEE} } @ARTICLE{Sheikh:15, author={H. R. Sheikh and A. C. Bovik}, journal={IEEE Transactions on Image Processing}, title={Image information and visual quality}, year={2006}, volume={15}, number={2}, pages={430-444}, keywords={image enhancement;visual perception;distorted image;human visual system;image information;image quality;quality assessment;signal fidelity measures;visual information fidelity;visual quality;Algorithm design and analysis;Distortion measurement;Humans;Image quality;Predictive models;Psychology;Quality assessment;Statistics;Video sharing;Visual system;Image information;image quality assessment (QA);information fidelity;natural scene statistics (NSS);Algorithms;Artificial Intelligence;Biomimetics;Humans;Image Enhancement;Image Interpretation, Computer-Assisted;Information Storage and Retrieval;Reproducibility of Results;Sensitivity and Specificity}, doi={10.1109/TIP.2005.859378}, ISSN={1057-7149}, month={Feb},} - @article{Thielemans:12, author={Kris Thielemans and Charalampos Tsoumpas and Sanida Mustafovic and Tobias Beisel and Pablo Aguiar and Nikolaos Dikaios and Matthew W Jacobson}, title={STIR: software for tomographic image reconstruction release 2}, journal={Physics in Medicine and Biology}, volume={57}, number={4}, pages={867}, url={http://stacks.iop.org/0031-9155/57/i=4/a=867}, year={2012}, abstract={We present a new version of STIR ( Software for Tomographic Image Reconstruction ), an open source object-oriented library implemented in C++ for 3D positron emission tomography reconstruction. This library has been designed such that it can be used for many algorithms and scanner geometries, while being portable to various computing platforms. This second release enhances its flexibility and modular design and includes additional features such as Compton scatter simulation, an additional iterative reconstruction algorithm and parametric image reconstruction (both indirect and direct). We discuss the new features in this release and present example results. STIR can be downloaded from http://stir.sourceforge.net [http://stir.sourceforge.net] .} } + @article{Thielemans:12, author={Kris Thielemans and Charalampos Tsoumpas and Sanida Mustafovic and Tobias Beisel and Pablo Aguiar and Nikolaos Dikaios and Matthew W Jacobson}, title={STIR: software for tomographic image reconstruction release 2}, journal={Physics in Medicine and Biology}, volume={57}, number={4}, pages={867}, url={http://stacks.iop.org/0031-9155/57/i=4/a=867}, year={2012}, abstract={We present a new version of STIR ( Software for Tomographic Image Reconstruction ), an open source object-oriented library implemented in C++ for 3D positron emission tomography reconstruction. This library has been designed such that it can be used for many algorithms and scanner geometries, while being portable to various computing platforms. This second release enhances its flexibility and modular design and includes additional features such as Compton scatter simulation, an additional iterative reconstruction algorithm and parametric image reconstruction (both indirect and direct). We discuss the new features in this release and present example results. STIR can be downloaded from http://stir.sourceforge.net [http://stir.sourceforge.net] .} } @article{Treeby:10, author = {Treeby, Bradley E. and Cox, B. T.}, title = {k-Wave: MATLAB toolbox for the simulation and reconstruction of photoacoustic wave fields}, journal = {Journal of Biomedical Optics}, volume = {15}, number = {2}, pages = {021314-021314-12}, abstract = {A new, freely available third party MATLAB toolbox for the simulation and reconstruction of photoacoustic wave fields is described. The toolbox, named k-Wave, is designed to make realistic photoacoustic modeling simple and fast. The forward simulations are based on a k-space pseudo-spectral time domain solution to coupled first-order acoustic equations for homogeneous or heterogeneous media in one, two, and three dimensions. The simulation functions can additionally be used as a flexible time reversal image reconstruction algorithm for an arbitrarily shaped measurement surface. A one-step image reconstruction algorithm for a planar detector geometry based on the fast Fourier transform (FFT) is also included. The architecture and use of the toolbox are described, and several novel modeling examples are given. First, the use of data interpolation is shown to considerably improve time reversal reconstructions when the measurement surface has only a sparse array of detector points. Second, by comparison with one-step, FFT-based reconstruction, time reversal is shown to be sufficiently general that it can also be used for finite-sized planar measurement surfaces. Last, the optimization of computational speed is demonstrated through parallel execution using a graphics processing unit.}, year = {2010}, isbn = {1083-3668}, doi = {10.1117/1.3360308}, URL = { http://dx.doi.org/10.1117/1.3360308}, eprint = {} } @@ -84,6 +84,28 @@ @inproceedings{wang:03 @article{wang:06, title={Modern image quality assessment}, author={Wang, Zhou and Bovik, Alan C}, journal={Synthesis Lectures on Image, Video, and Multimedia Processing}, volume={2}, number={1}, pages={1--156}, year={2006}, publisher={Morgan \& Claypool Publishers} } +@article{wang:02, + title={A universal image quality index}, + author={Wang, Zhou and Bovik, Alan C}, + journal={IEEE signal processing letters}, + volume={9}, + number={3}, + pages={81--84}, + year={2002}, + publisher={IEEE} +} + @article{Wu:13, title = "A phase retrieval algorithm for X-ray phase contrast imaging ", journal = "Optik - International Journal for Light and Electron Optics ", volume = "124", number = "9", pages = "864 - 866", year = "2013", note = "", issn = "0030-4026", doi = "http://dx.doi.org/10.1016/j.ijleo.2012.02.030", url = "http://www.sciencedirect.com/science/article/pii/S0030402612001635", author = "Jie Wu and Jiabi Chen", keywords = "Phase retrieval", keywords = "Fourier transform", keywords = "X-ray", keywords = "Image intensity ", abstract = "Based on the transport-of-intensity equation and the Fourier transform, a rapid phase retrieval algorithm for X-ray phase contrast imaging is described in detail. This algorithm is a non-iterative phase retrieval method, and it has a potential speed for large scale X-ray phase contrast images. Then the numerical simulation is made to evaluate the rapid phase retrieval algorithm performance. Finally, a real fiber material experiment is carried out using a micro focus X-ray phase contrast imaging experiment platform, and the phase distribution image is calculated out by this algorithm. The result shows that this phase retrieval algorithm is effective and optional to practical application. " } @article{Yin:12, title = "Understanding the phase contrast optics to restore artifact-free microscopy images for segmentation ", journal = "Medical Image Analysis ", volume = "16", number = "5", pages = "1047 - 1062", year = "2012", note = "", issn = "1361-8415", doi = "http://dx.doi.org/10.1016/j.media.2011.12.006", url = "http://www.sciencedirect.com/science/article/pii/S1361841512000035", author = "Zhaozheng Yin and Takeo Kanade and Mei Chen", keywords = "Phase contrast optics", keywords = "Microscopy image analysis", keywords = "Imaging model", keywords = "Image restoration", keywords = "Image segmentation ", abstract = "Phase contrast, a noninvasive microscopy imaging technique, is widely used to capture time-lapse images to monitor the behavior of transparent cells without staining or altering them. Due to the optical principle, phase contrast microscopy images contain artifacts such as the halo and shade-off that hinder image segmentation, a critical step in automated microscopy image analysis. Rather than treating phase contrast microscopy images as general natural images and applying generic image processing techniques on them, we propose to study the optical properties of the phase contrast microscope to model its image formation process. The phase contrast imaging system can be approximated by a linear imaging model. Based on this model and input image properties, we formulate a regularized quadratic cost function to restore artifact-free phase contrast images that directly correspond to the specimen’s optical path length. With artifacts removed, high quality segmentation can be achieved by simply thresholding the restored images. The imaging model and restoration method are quantitatively evaluated on microscopy image sequences with thousands of cells captured over several days. We also demonstrate that accurate restoration lays the foundation for high performance in cell detection and tracking. " } @article{zanaga:16, title={Quantitative 3D analysis of huge nanoparticle assemblies}, author={Zanaga, Daniele and Bleichrodt, Folkert and Altantzis, Thomas and Winckelmans, Naomi and Palenstijn, Willem Jan and Sijbers, Jan and de Nijs, Bart and van Huis, Marijn A and S{\'a}nchez-Iglesias, Ana and Liz-Marz{\'a}n, Luis M and others}, journal={Nanoscale}, volume={8}, number={1}, pages={292--299}, year={2016}, publisher={Royal Society of Chemistry} } + +@article{zhang:11, + title={FSIM: a feature similarity index for image quality assessment}, + author={Zhang, Lin and Zhang, Lei and Mou, Xuanqin and Zhang, David}, + journal={IEEE transactions on Image Processing}, + volume={20}, + number={8}, + pages={2378--2386}, + year={2011}, + publisher={IEEE} +} diff --git a/docs/source/conf.py b/docs/source/conf.py index a62908a..fdb0937 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -308,14 +308,13 @@ #texinfo_appendices = [] # If false, no module index is generated. -#texinfo_domain_indices = True +# texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' +# texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False - +# texinfo_no_detailmenu = False # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'https://docs.python.org/': None} diff --git a/docs/source/index.rst b/docs/source/index.rst index bd9b977..f8e8720 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -2,14 +2,14 @@ XDesign ####### **XDesign** is an open-source Python package for generating -configurable simulation phantoms for benchmarking tomographic +configurable simulation phantoms for benchmarking tomographic image reconstruction. .. toctree:: :maxdepth: 1 api - refs + zrefs Features ======== @@ -17,7 +17,7 @@ Features * Configurable analytic 2D phantoms. * Various visualization tools for statistics. * Analytic projection operators. - + Contribute ========== @@ -29,7 +29,7 @@ Contribute License ======= -The project is licensed under the +The project is licensed under the `BSD-3 `_ license. Indices and tables diff --git a/docs/source/refs.rst b/docs/source/zrefs.rst similarity index 88% rename from docs/source/refs.rst rename to docs/source/zrefs.rst index 1f70608..2690cb3 100644 --- a/docs/source/refs.rst +++ b/docs/source/zrefs.rst @@ -4,4 +4,4 @@ References .. bibliography:: bibtex/refs.bib :style: plain - :all: + :cited: diff --git a/xdesign/feature.py b/xdesign/feature.py index 8bda683..edcb905 100644 --- a/xdesign/feature.py +++ b/xdesign/feature.py @@ -62,12 +62,18 @@ class Feature(object): '''A geometric region(s) and associated materials properti(es). - Properties and geometry can be manipulated from this level, but rendering - must access the geometry directly. + + Features represent regions of uniform materials properties within a :class:`.Phantom`. Each Feature consists of a geometry which defines the region in which some given materials properties e.g. mass attenuation, density, crystal structure, color... have a certain value. By collecting Features together, Phantoms can have varying properites across a space. + + A geometric entity must be supplied at construction. All features are given + a mass attenuation (:attr:`mass_atten`) of 1 by default. + + .. note:: Currently, properties must be constant across the Feature, but perhaps in the future, there will be support for peicewise definition of continuous property functions. e.g. a circle whose density follows a + gaussian profile. Attributes - ---------------- - geometry : Entity + ---------- + geometry : :class:`.Entity` Defines a region where the properties are valid. mass_atten : scalar The mass attenuation coefficient of the Feature. @@ -79,39 +85,34 @@ def __init__(self, geometry, mass_atten=1): self.mass_atten = mass_atten def add_property(self, name, function): - """Adds a property by name to the Feature. - NOTE: Properties added here are not cached because they are probably - never called with the same parameters ever or the property is static - so it doesnt need caching. - """ + """Adds a property by name to the Feature.""" + # NOTE: Properties added here are not cached because they are probably never called with the same parameters ever or the property is static so it doesnt need caching. setattr(self, name, function) @property def center(self): - """Returns the centroid of the feature.""" + """Returns the centroid of the Feature.""" return self.geometry.center @property def radius(self): - """Returns the radius of the smallest boundary circle""" + """Returns the radius of the smallest boundary circle.""" return self.geometry.radius @property def area(self): - """Returns the total surface area of the feature""" + """Returns the total surface area of the Feature.""" return self.geometry.area @property def volume(self): - """Returns the volume of the feature""" + """Returns the volume of the Feature""" return self.geometry.volume def translate(self, x, y): - """Translate feature geometry. Translating property functions is not - supported.""" + """Translates the geometry. Translating the property functions is not supported.""" self.geometry.translate(x, y) - def rotate(self, theta, p, axis=None): - """Rotate feature geometry around a line. Rotating property - functions is not supported.""" - self.geometry.rotate(theta, p) + def rotate(self, theta, point=None, axis=None): + """Rotate the geometry around an axis that passes through the given point. Rotating property functions is not supported.""" + self.geometry.rotate(theta, point, axis) diff --git a/xdesign/geometry.py b/xdesign/geometry.py index c4e4ece..ea8532b 100644 --- a/xdesign/geometry.py +++ b/xdesign/geometry.py @@ -167,7 +167,9 @@ def z(self): @property def norm(self): - """Reference: http://stackoverflow.com/a/23576322""" + """Calculates the euclidian (L2) norm of the vector to the point.""" + # See http://stackoverflow.com/a/23576322 for a discussion of the + # quickest way to calculate the norm of a vector. return sqrt(self._x.dot(self._x)) @property @@ -182,7 +184,7 @@ def translate(self, vector): self._x += vector def rotate(self, theta, point=None, axis=None): - """Rotate entity around an axis by theta radians.""" + """Rotates entity around an axis by theta radians.""" if not isinstance(theta, Number): raise TypeError("theta must be scalar.") if point is None: diff --git a/xdesign/metrics.py b/xdesign/metrics.py index 0aee395..1a4bec8 100644 --- a/xdesign/metrics.py +++ b/xdesign/metrics.py @@ -140,7 +140,7 @@ def compute_mtf2(phantom, image): def compute_mtf(phantom, image, Ntheta=4): - '''Uses method described in Friedman et al to calculate the MTF. + '''Uses method described in :cite:`Friedman:13` to calculate the MTF. Parameters --------------- @@ -159,14 +159,6 @@ def compute_mtf(phantom, image, Ntheta=4): MTF values bin_centers : ndarray the center of the bins if Ntheta >= 1 - - References - --------------- - S. N. Friedman, G. S. K. Fung, J. H. Siewerdsen, and B. M. W. Tsui. "A - simple approach to measure computed tomography (CT) modulation transfer - function (MTF) and noise-power spectrum (NPS) using the American College - of Radiology (ACR) accreditation phantom," Med. Phys. 40, 051907-1 - - 051907-9 (2013). http://dx.doi.org/10.1118/1.4800795 ''' if not isinstance(phantom, UnitCircle): raise TypeError('MTF requires unit circle phantom.') @@ -429,19 +421,9 @@ def periodic_function(p, x): return value - def compute_nps(phantom, A, B=None, plot_type='frequency'): - '''Calculates the noise power spectrum from a unit circle image. The peak - at low spatial frequency is probably due to aliasing. Invesigation into - supressing this peak is necessary. - - References - --------------- - S. N. Friedman, G. S. K. Fung, J. H. Siewerdsen, and B. M. W. Tsui. "A - simple approach to measure computed tomography (CT) modulation transfer - function (MTF) and noise-power spectrum (NPS) using the American College - of Radiology (ACR) accreditation phantom," Med. Phys. 40, 051907-1 - - 051907-9 (2013). http://dx.doi.org/10.1118/1.4800795 + '''Calculates the noise power spectrum from a unit circle image using the + method from :cite:`Friedman:13`. Parameters ---------- @@ -536,7 +518,7 @@ def compute_nps(phantom, A, B=None, plot_type='frequency'): def compute_neq(phantom, A, B): - '''Calculates the NEQ according to recommendations by JT Dobbins. + '''Calculates the NEQ according to recommendations by :cite:`Dobbins:95`. Parameters ---------- @@ -810,7 +792,9 @@ def sort(self): def compute_quality(reference, reconstructions, method="MSSSIM", L=1): """ - Computes image quality metrics for each of the reconstructions. + Computes full-reference image quality metrics for each of the reconstructions. + + Available methods include SSIM :cite:`wang:02`, MSSSIM :cite:`wang:03`, VIFp :cite:`Sheikh:15`, and FSIM :cite:`zhang:11`. Parameters --------- @@ -822,7 +806,7 @@ def compute_quality(reference, reconstructions, method="MSSSIM", L=1): A list of discrete reconstructions method : string, optional The quality metric desired for this comparison. - Options include: SSIM, MSSSIM + Options include: SSIM, MSSSIM, VIFp, FSIM L : scalar The dynamic range of the data. This value is 1 for float representations and 2^bitdepth for integer representations. diff --git a/xdesign/phantom.py b/xdesign/phantom.py index 316ecc5..652ec6c 100644 --- a/xdesign/phantom.py +++ b/xdesign/phantom.py @@ -67,18 +67,22 @@ class Phantom(object): - """Phantom generation class. + """Phantoms are objects for the purpose of evaluating an imaging method. + + Each Phantom is a square or circular region containing a :class:`.list` of :class:`.Feature` objects. The :mod:`.acquisition` module uses Phantoms as an interface for generating data. + + Phantoms can be combined using the '+' operator, and they also have some of the same mehtods as the :class:`.List` class including: append, pop, insert, sort, and reverse. Attributes ---------- - shape : string - Shape of the phantom. Available options: circle, square. + shape : :class:`str` + The shape of the phantom: circle, square. population : scalar - Number of generated features in the phantom. + The number of :class:`.Feature` in the Phantom. area : scalar - Area of the features in the phantom. - feature : list - List of features. + The total volume of the :class:`.Feature` in the Phantom. + feature : :class:`list` + List of :class:`.Feature`. """ # OPERATOR OVERLOADS def __init__(self, shape='circle'): @@ -100,13 +104,14 @@ def __add__(self, other): # PROPERTIES @property def list(self): + """Prints the contents of the Phantom.""" for m in range(self.population): print(self.feature[m].list) @property def density(self): - '''Returns the area density of the phantom. (Does not acount for - mass_atten.) + '''Returns the area density of the phantom. Does not acount for + functional weight of the Features. ''' if self.shape == 'square': return self.area @@ -115,7 +120,7 @@ def density(self): # FEATURE LIST MANIPULATION def append(self, feature): - """Add a feature to the top of the phantom.""" + """Add a Feature to the top of the phantom.""" if not isinstance(feature, Feature): raise TypeError("Can only add Features to Phantoms.") self.feature.append(feature) @@ -123,13 +128,13 @@ def append(self, feature): self.population += 1 def pop(self, i=-1): - """Pop i-th feature from the phantom.""" + """Pop the i-th Feature from the Phantom.""" self.population -= 1 self.area -= self.feature[i].area return self.feature.pop(i) def insert(self, i, feature): - """Insert a feature at a given depth.""" + """Insert a Feature at a given depth.""" if not isinstance(feature, Feature): raise TypeError("Can only add Features to Phantoms.") self.feature.insert(i, feature) @@ -137,7 +142,7 @@ def insert(self, i, feature): self.population += 1 def sort(self, param="mass_atten", reverse=False): - """Sorts the features by mass_atten or size""" + """Sorts the Features by a property such as mass_atten or size.""" if param == "mass_atten": def key(feature): return feature.mass_atten elif param == "size": @@ -147,13 +152,12 @@ def key(feature): return feature.area self.feature = sorted(self.feature, key=key, reverse=reverse) def reverse(self): - """Reverse the features of the phantom""" + """Reverse the order of the Features in the phantom.""" self.feature.reverse() def sprinkle(self, counts, radius, gap=0, region=None, mass_atten=1, max_density=1): - """Sprinkle a number of circles. Uses various termination criteria to - determine when to stop trying to add circles. + """Sprinkles a number of :class:`.Circle` shaped Features around the Phantom. Uses various termination criteria to determine when to stop trying to add circles. Parameters ---------- @@ -164,12 +168,10 @@ def sprinkle(self, counts, radius, gap=0, region=None, mass_atten=1, gap : float, optional The minimum distance between circle boundaries. A negative value allows overlapping edges. - region : Entity, optional - The new circles are confined to this shape. None if the circles are - allowed anywhere. + region : :class:`.Entity`, optional + The new circles are confined to this shape. None if the circles are allowed anywhere. max_density : scalar, optional - Stops adding circles when the geometric density of the phantom - reaches this ratio. + Stops adding circles when the geometric density of the phantom reaches this ratio. mass_atten : scalar, optional A mass attenuation parameter passed to the circles. @@ -234,7 +236,9 @@ def translate(self, dx, dy): self.feature[m].translate(dx, dy) def rotate(self, theta, origin=Point([0.5, 0.5]), axis=None): - """Rotate phantom around a point.""" + """ + Rotates the Phantom around an axis passing through the given origin. + """ for m in range(self.population): self.feature[m].rotate(theta, origin, axis) @@ -252,7 +256,7 @@ def numpy(self): return arr def save(self, filename): - """Save phantom to file.""" + """Saves phantom to file.""" np.savetxt(filename, self.numpy(), delimiter=',') def load(self, filename): diff --git a/xdesign/plot.py b/xdesign/plot.py index 0b639c2..729fee3 100644 --- a/xdesign/plot.py +++ b/xdesign/plot.py @@ -102,17 +102,24 @@ def plot_phantom(phantom, axis=None, labels=None, c_props=[], c_map=None): - """Plots a phantom to the given axis. + """Plots a :class:`.Phantom` to the given axis. Parameters ---------- + phantom : :class:`.Phantom` + A phantom to be plotted. + axis : :class:`matplotlib.axis.Axis` + The axis where the phantom should be plotted. `None` creates + a new axis. labels : bool, optional - Each feature is numbered according to its index in the phantom. + `True` : Each :class:`.Feature` is numbered according to its index in + the :class:`.Phantom`. c_props : list of str, optional - List of feature properties to use for colormapping the geometries. + List of :class:`.Feature` properties to use for colormapping the + geometries. c_map : function, optional - A function which takes the a list of prop(s) for a Feature as input and - returns a matplolib color specifier. + A function which takes the list of prop(s) for a :class:`.Feature` as + input and returns a matplolib color specifier. :cite:`Hunter:07` """ # IDEA: Allow users to provide list or generator for labels. if not isinstance(phantom, Phantom): @@ -149,14 +156,19 @@ def plot_phantom(phantom, axis=None, labels=None, c_props=[], c_map=None): def plot_feature(feature, axis=None, alpha=None, c=None): - """Plots a feature on the given axis. + """Plots a :class:`.Feature` on the given axis. Parameters ---------- - alpha : float + feature : :class:`.Feature` + A Feature to plot on the given axis. + axis : :class:`matplotlib.axis.Axis`, optional + The axis where the Feature should be plotted. `None` creates + a new axis. + alpha : :class:`.float`, optional The plot opaqueness. 0 is transparent. 1 is opaque. - c : matplotlib color specifier - See http://matplotlib.org/api/colors_api.html + c : :mod:`matplotlib.color`, optional + The color of the plotted Feature. """ if not isinstance(feature, Feature): raise TypeError('Can only plot Features.') @@ -175,14 +187,19 @@ def plot_feature(feature, axis=None, alpha=None, c=None): def plot_mesh(mesh, axis=None, alpha=None, c=None): - """Plots a mesh to the given axis. + """Plots a :class:`.Mesh` to the given axis. Parameters ---------- - alpha : float + mesh : :class:`.Mesh` + A Mesh to plot on the given axis. + axis : :class:`matplotlib.axis.Axis`, optional + The axis where the Mesh should be plotted. `None` creates + a new axis. + alpha : :class:`.float`, optional The plot opaqueness. 0 is transparent. 1 is opaque. - c : matplotlib color specifier - See http://matplotlib.org/api/colors_api.html + c : :mod:`matplotlib.color`, optional + The color of the plotted Mesh. """ assert(isinstance(mesh, Mesh)) if axis is None: @@ -194,14 +211,19 @@ def plot_mesh(mesh, axis=None, alpha=None, c=None): def plot_polygon(polygon, axis=None, alpha=None, c=None): - """Plots a polygon to the given axis. + """Plots a :class:`.Polygon` to the given axis. Parameters ---------- - alpha : float + polygon : :class:`.Polygon` + A Polygon to plot on the given axis. + axis : :class:`matplotlib.axis.Axis`, optional + The axis where the Polygon should be plotted. `None` creates + a new axis. + alpha : :class:`.float`, optional The plot opaqueness. 0 is transparent. 1 is opaque. - c : matplotlib color specifier - See http://matplotlib.org/api/colors_api.html + c : :mod:`matplotlib.color`, optional + The color of the plotted Polygon. """ assert(isinstance(polygon, Polygon)) if axis is None: @@ -218,14 +240,19 @@ def plot_polygon(polygon, axis=None, alpha=None, c=None): def plot_curve(curve, axis=None, alpha=None, c=None): - """Plots a curve to the given axis. + """Plots a :class:`.Curve' to the given axis. Parameters ---------- - alpha : float + curve : :class:`.Curve` + A Curve to plot on the given axis. + axis : :class:`matplotlib.axis.Axis`, optional + The axis where the Curve should be plotted. None creates + a new axis. + alpha : :class:`.float`, optional The plot opaqueness. 0 is transparent. 1 is opaque. - c : matplotlib color specifier - See http://matplotlib.org/api/colors_api.html + c : :mod:`matplotlib.color`, optional + The color of the plotted curve. """ assert(isinstance(curve, Curve)) if axis is None: @@ -242,7 +269,8 @@ def plot_curve(curve, axis=None, alpha=None, c=None): def _make_axis(): - """Makes an axis for plotting phantom module classes.""" + """Makes an :class:`matplotlib.axis.Axis` for plotting :mod:`.Phantom` module + classes.""" fig = plt.figure(figsize=(8, 8), facecolor='w') axis = fig.add_subplot(111, aspect='equal') plt.grid('on') @@ -252,10 +280,11 @@ def _make_axis(): def discrete_phantom(phantom, size, ratio=8, uniform=True, prop='mass_atten'): """Returns discrete representation of the property function, prop, in the - phantom. The values of overlapping features are additive. + :class:`.Phantom`. The values of overlapping Features are additive. Parameters ---------- + phantom: :class:`.Phantom` size : scalar The side length in pixels of the resulting square image. ratio : scalar, optional @@ -272,7 +301,7 @@ def discrete_phantom(phantom, size, ratio=8, uniform=True, prop='mass_atten'): Returns ------- image : numpy.ndarray - The discrete representation of the phantom that is size x size. + The discrete representation of the :class:`.Phantom` that is size x size. """ if not isinstance(phantom, Phantom): raise TypeError('phantom must be type Phantom.') @@ -312,8 +341,8 @@ def discrete_phantom(phantom, size, ratio=8, uniform=True, prop='mass_atten'): def _discrete_feature(feature, image, px, py, prop): - """Helper function for discrete_phantom. Rasterizes the geometry of the - feature.""" + """Helper function for :func:`.discrete_phantom`. Rasterizes the geometry + of the feature.""" size = px.shape x = np.vstack([px.flatten(), py.flatten()]).T new_feature = feature.geometry.contains(x) * getattr(feature, prop) @@ -323,7 +352,7 @@ def _discrete_feature(feature, image, px, py, prop): def sidebyside(p, size=100, labels=None, prop='mass_atten'): '''Displays the geometry and the discrete property function of - the given phantom side by side.''' + the given :class:`.Phantom` side by side.''' fig = plt.figure(figsize=(6, 3), dpi=600) axis = fig.add_subplot(121, aspect='equal') plt.grid('on') From 1b4085997a6601a89bde3c8b6064edac8b225767 Mon Sep 17 00:00:00 2001 From: Daniel Ching Date: Sun, 27 Nov 2016 21:55:44 -0800 Subject: [PATCH 4/5] Adding more things to the documentation. --- docs/source/api/xdesign.geometry.rst | 9 +- xdesign/geometry.py | 227 ++++++++++++++++----------- 2 files changed, 137 insertions(+), 99 deletions(-) diff --git a/docs/source/api/xdesign.geometry.rst b/docs/source/api/xdesign.geometry.rst index 8d547c7..20dbecc 100644 --- a/docs/source/api/xdesign.geometry.rst +++ b/docs/source/api/xdesign.geometry.rst @@ -4,21 +4,22 @@ .. automodule:: xdesign.geometry :members: :show-inheritance: + :inherited-members: :undoc-members: :synopsis: Defines geometric objects for the purpose of supporting :class:`.Feature` definition and calculating intersections for the :mod:`.acquisition` module. - .. rubric:: **Functions:** + .. rubric:: **Classes:** .. autosummary:: - + Entity Point - Superellipse - Ellipse Circle Line + Polygon Triangle Rectangle Square + Mesh .. moduleauthor:: Doga Gursoy .. moduleauthor:: Daniel J Ching diff --git a/xdesign/geometry.py b/xdesign/geometry.py index ea8532b..539a7ab 100644 --- a/xdesign/geometry.py +++ b/xdesign/geometry.py @@ -79,67 +79,100 @@ class Entity(object): """Base class for all geometric entities. All geometric entities should - have these methods.""" + have these attributes and methods.""" def __init__(self): self._dim = 0 def __str__(self): - """A string representation for easier debugging.""" + """A string representation for easier debugging. + + .. note:: + This method is inherited from :class:`.Entity` which means it is + not implemented and will throw an error. + """ raise NotImplementedError @property def dim(self): - """The dimensionality of the entity""" + """The dimensionality of the points which describe the entity. + """ return self._dim def translate(self, vector): - """Translate entity along vector.""" + """Translates the entity in the direction of a vector. + + .. note:: + This method is inherited from :class:`.Entity` which means it is + not implemented and will throw an error. + """ raise NotImplementedError def rotate(self, theta, point=None, axis=None): - """Rotate entity around an axis which passes through a point by theta - radians.""" + """Rotates the entity theta radians around an axis defined by a point + and a vector + + .. note:: + This method is inherited from :class:`.Entity` which means it is + not implemented and will throw an error. + """ raise NotImplementedError def scale(self, vector): - """Scale entity in each dimension according to vector. Scaling is - centered on the origin.""" + """Scales the entity in each dimension according to vector. Scaling is + centered on the origin. + + .. note:: + This method is inherited from :class:`.Entity` which means it is + not implemented and will throw an error. + """ raise NotImplementedError def contains(self, point): - """Returns True if the point(s) is within the bounds of the entity. - point is either a Point or an N points listed as an NxD array.""" + """Returns True if the given point(s) is within the bounds of the + entity. + + Points are either a single :class:`.Point` or given as an + :class:`.ndarray`. + + .. note:: + This method is inherited from :class:`.Entity` which means it is + not implemented and will throw an error. + """ raise NotImplementedError def collision(self, other): - """Returns True if this entity collides with another entity.""" + """Returns True if this entity collides with another entity. + + .. note:: + This method is inherited from :class:`.Entity` which means it is + not implemented and will throw an error. + """ raise NotImplementedError def distance(self, other): - """Return the closest distance between entities.""" + """Returns the closest distance between entities. + + .. note:: + This method is inherited from :class:`.Entity` which means it is + not implemented and will throw an error. + """ raise NotImplementedError def midpoint(self, other): - """Return the midpoint between entities.""" + """Returns the midpoint between entities.""" return self.distance(other) / 2. class Point(Entity): """A point in ND cartesian space. + Takes either a 1D array-like object as the parameter for construction. + Attributes ---------- - _x : 1darray + _x : :class:`.ndarray` ND coordinates of the point. - x : scalar - dimension 0 of the point. - y : scalar - dimension 1 of the point. - z : scalar - dimension 2 of the point. - norm : scalar - The L2/euclidian norm of the point. """ def __init__(self, x): if not isinstance(x, (list, np.ndarray)): @@ -155,14 +188,17 @@ def __str__(self): @property def x(self): + """Dimension 0 of the point.""" return self._x[0] @property def y(self): + """Dimension 1 of the point.""" return self._x[1] @property def z(self): + """Dimension 2 of the point.""" return self._x[2] @property @@ -172,19 +208,16 @@ def norm(self): # quickest way to calculate the norm of a vector. return sqrt(self._x.dot(self._x)) - @property - def dim(self): - return self._dim - def translate(self, vector): - """Translate point along vector.""" + """Translates the point along the given vector.""" if not isinstance(vector, (list, np.ndarray)): raise TypeError("vector must be arraylike.") self._x += vector def rotate(self, theta, point=None, axis=None): - """Rotates entity around an axis by theta radians.""" + """Rotates the point theta radians around the axis defined by the given + point and axis.""" if not isinstance(theta, Number): raise TypeError("theta must be scalar.") if point is None: @@ -194,7 +227,8 @@ def rotate(self, theta, point=None, axis=None): else: raise TypeError("center of rotation must be Point.") if axis is not None: - raise NotImplementedError + raise NotImplementedError("Rotation about axis besides [0 0 1] are" + " not implemented.") # shift rotation center to origin self._x -= center @@ -206,15 +240,16 @@ def rotate(self, theta, point=None, axis=None): self._x += center def scale(self, vector): - """Scale entity in each dimension according to vector. Scaling is - centered on the origin.""" + """Scales the coordinates of the point in each dimension according to + the given vector. Scaling is centered on the origin.""" if not isinstance(vector, (List, np.ndarray)): raise TypeError("vector must be arraylike.") self._x *= vector def contains(self, other): - """Returns True if the other is within the bounds of the entity.""" + """Returns True if the other is within the bounds of the Point. Points + can only contain other Points.""" if isinstance(other, Point): return self == point if isinstance(other, np.ndarray): @@ -223,14 +258,14 @@ def contains(self, other): return False def collision(self, other): - """Returns True if this entity collides with another entity.""" + """Returns True if this Point collides with another entity.""" if isinstance(other, Point): return self == point else: raise NotImplementedError def distance(self, other): - """Return the closest distance between entities.""" + """Returns the closest distance between entities.""" if not isinstance(other, Point): raise NotImplementedError("Point to point distance only.") d = self._x - other._x @@ -271,27 +306,23 @@ def __hash__(self): class LinearEntity(Entity): - """Base class for linear entities in 2-D Cartesian space. + """Base class for linear entities in 2D Cartesian space. e.g. :class:`.Line`, + :class:`.Segment`, and :class:`.Ray`. + + The constructor takes two unique :class:`.Point`. Attributes ---------- p1 : Point p2 : Point - vertical : bool - horizontal : bool - slope : scalar - points : list - normal : Point - tangent : Point - dim : scalar """ def __init__(self, p1, p2): if not isinstance(p1, Point) or not isinstance(p2, Point): - raise TypeError("p1 and p2 must be points") + raise TypeError("p1 and p2 must be Points") if p1 == p2: - raise ValueError('Requires two unique points.') + raise ValueError('Requires two unique Points.') if p1.dim != p2.dim: - raise ValueError('Two points must have same dimensionality.') + raise ValueError('Two Points must have same dimensionality.') self.p1 = p1 self.p2 = p2 self._dim = p1.dim @@ -311,7 +342,7 @@ def horizontal(self): @property def slope(self): - """Return the slope of the line.""" + """Returns the slope of the line.""" if self.vertical: return np.inf else: @@ -320,7 +351,8 @@ def slope(self): @property def points(self): - """The two points used to define this linear entity.""" + """Returns the two points used to define this linear entity as a + 2-tuple.""" return (self.p1, self.p2) # @property @@ -334,18 +366,18 @@ def points(self): @property def length(self): - """Returns the length of the segment""" + """Returns the length of the segment between p1 and p2.""" return self.p1.distance(self.p2) @property def tangent(self): - """Return unit tangent vector.""" + """Returns the unit tangent vector.""" dx = (self.p2._x - self.p1._x) / self.length return Point(dx) @property def normal(self): - """Return unit normal vector.""" + """Return the unit normal vector.""" dx = (self.p2._x - self.p1._x) / self.length R = np.array([[0, 1], [-1, 0]]) @@ -354,35 +386,32 @@ def normal(self): @property def numpy(self): - """Return list representation.""" + """Returns an array of coordinates where the first row is p1 and the + second row is p2.""" return np.vstack((self.p1._x, self.p2._x)) @property def list(self): - """Return list representation.""" + """Returns an list of coordinates where p1 is the first D coordinates + and p2 is the next D coordinates.""" return np.hstack((self.p1._x, self.p2._x)) - @property - def dim(self): - """The dimensionality of the entity""" - return self._dim - def translate(self, vector): - """Translate entity along vector.""" + """Translates the :class:`.LinearEntity` by the given vector.""" self.p1.translate(vector) self.p2.translate(vector) def rotate(self, theta, point=None, axis=None): - """Rotate entity around an axis which passes through an point by theta - radians.""" + """Rotates the :class:`.LinearEntity` by theta radians around an axis + defined by an axis and a point.""" self.p1.rotate(theta, point, axis) self.p2.rotate(theta, point, axis) class Line(LinearEntity): - """Line in 2-D cartesian space. + """Line in 2D cartesian space. - It is defined by two distinct points. + The constructor takes two unique :class:`.Point`. Attributes ---------- @@ -441,8 +470,8 @@ def standard(self): return calc_standard(A) def distance(self, other): - """Return the closest distance between entities. - REF: http://geomalgorithms.com/a02-_lines.html""" + """Returns the closest distance between entities.""" + # REF: http://geomalgorithms.com/a02-_lines.html if not isinstance(other, Point): raise NotImplementedError("Line to point distance only.") d = np.cross(self.tangent._x, other._x - self.p1._x) @@ -498,8 +527,8 @@ def distance(self, other): class Curve(Entity): - """Base class for entities whose surface can be defined by a continuous - equation. + """The base class for closed manifolds defined by a single equation. e.g. + :class:`.Circle`, :class:`.Sphere`, or :class:`.Torus`. Attributes ---------- @@ -512,19 +541,19 @@ def __init__(self, center): self.center = center def translate(self, vector): - """Translate point along vector.""" + """Translates the Curve along a vector.""" if not isinstance(vector, (Point, list, nd.array)): raise TypeError("vector must be point, list, or array.") self.center.translate(vector) def rotate(self, theta, point=None, axis=None): - """Rotate entity around an axis which passes through a point by theta - radians.""" + """Rotates the Curve by theta radians around an axis which passes + through a point radians.""" self.center.rotate(theta, point, axis) class Superellipse(Curve): - """Superellipse in 2-D cartesian space. + """A Superellipse in 2D cartesian space. Attributes ---------- @@ -581,14 +610,14 @@ def scale(self, val): class Circle(Curve): - """Circle in 2-D cartesian space. + """Circle in 2D cartesian space. Attributes ---------- center : Point - Defines the center point of the circle. + The center point of the circle. radius : scalar - Radius of the circle. + The radius of the circle. """ def __init__(self, center, radius): @@ -596,7 +625,7 @@ def __init__(self, center, radius): self.radius = float(radius) def __str__(self): - """Return analytical equation.""" + """Return the analytical equation.""" return "(x-%s)^2 + (y-%s)^2 = %s^2" % (self.center.x, self.center.y, self.radius) @@ -611,30 +640,34 @@ def list(self): @property def circumference(self): - """Return circumference.""" + """Returns the circumference.""" return 2 * np.pi * self.radius @property def diameter(self): - """Return diameter.""" + """Returns the diameter.""" return 2 * self.radius @property def area(self): - """Return area.""" + """Return the area.""" return np.pi * self.radius**2 @property def patch(self): + """Returns a matplotlib patch.""" return plt.Circle((self.center.x, self.center.y), self.radius) - def scale(self, val): - """Scale.""" - raise NotImplementedError - # self.center.scale(val) - # self.rad *= val + # def scale(self, val): + # """Scale.""" + # raise NotImplementedError + # self.center.scale(val) + # self.rad *= val def contains(self, points): + """Returns whether a point or array of points are within the boundaries + of the Circle. + """ if isinstance(points, Point): x = p._x elif isinstance(points, np.ndarray): @@ -646,13 +679,14 @@ def contains(self, points): class Polygon(Entity): - """A convex polygon in 2-D cartesian space. + """A convex polygon in 2D cartesian space. - It is defined by a number of distinct points. + It is defined by a number of distinct vertices of class :class:`.Point`. + Superclasses include :class:`.Square`, :class:`.Triangle`, etc. Attributes ---------- - vertices : sequence of Points + vertices : List of Points """ def __init__(self, vertices): @@ -689,12 +723,12 @@ def numpy(self): @property def area(self): - """Return the area of the entity.""" + """Returns the area of the Polygon.""" raise NotImplementedError @property def perimeter(self): - """Return the perimeter of the entity.""" + """Return the perimeter of the Polygon.""" perimeter = 0 verts = self.vertices points = verts + [verts[0]] @@ -704,8 +738,8 @@ def perimeter(self): @property def bounds(self): - """Return a tuple (xmin, ymin, xmax, ymax) representing the - bounding rectangle for the geometric figure. + """Returns a 4-tuple (xmin, ymin, xmax, ymax) representing the + bounding rectangle for the Polygon. """ xs = [p.x for p in self.vertices] ys = [p.y for p in self.vertices] @@ -713,20 +747,23 @@ def bounds(self): @property def patch(self): + """Returns a matplotlib patch.""" return plt.Polygon(self.numpy) def translate(self, vector): - """Translate polygon.""" + """Translates the polygon by a vector.""" for v in self.vertices: v.translate(vector) def rotate(self, theta, point=None, axis=None): - """Rotate entity around an axis which passes through a point by theta - radians.""" + """Rotates the Polygon around an axis which passes through a point by + theta radians.""" for v in self.vertices: v.rotate(theta, point, axis) def contains(self, points): + """Returns whether the given points are contained within the Polygon. + """ if isinstance(points, Point): x = p._x elif isinstance(points, np.ndarray): @@ -758,7 +795,7 @@ def half_space(self): class Triangle(Polygon): - """Triangle in 2-D cartesian space. + """Triangle in 2D cartesian space. It is defined by three distinct points. """ @@ -784,7 +821,7 @@ def area(self): class Rectangle(Polygon): - """Rectangle in 2-D cartesian space. + """Rectangle in 2D cartesian space. It is defined by four distinct points. """ @@ -809,7 +846,7 @@ def area(self): class Square(Rectangle): - """Square in 2-D cartesian space. + """Square in 2D cartesian space. It is defined by a center and a side length. """ From 3d5a4d5e931a3f6f75601c8ed80e439cb68958b7 Mon Sep 17 00:00:00 2001 From: Daniel Ching Date: Sun, 8 Jan 2017 22:18:43 -0800 Subject: [PATCH 5/5] Tweaking Note statement. --- xdesign/feature.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xdesign/feature.py b/xdesign/feature.py index edcb905..cc61d0c 100644 --- a/xdesign/feature.py +++ b/xdesign/feature.py @@ -68,8 +68,7 @@ class Feature(object): A geometric entity must be supplied at construction. All features are given a mass attenuation (:attr:`mass_atten`) of 1 by default. - .. note:: Currently, properties must be constant across the Feature, but perhaps in the future, there will be support for peicewise definition of continuous property functions. e.g. a circle whose density follows a - gaussian profile. + .. note:: Currently, properties must be constant across the Feature, but perhaps in the future, there will be support for peicewise definition of continuous property functions. e.g. a circle whose density follows a gaussian profile. Attributes ----------