diff --git a/.gitignore b/.gitignore index e7b0598..1fc326e 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,21 @@ var/ .installed.cfg *.egg +# pytest cache +.pytest_cache + +# package and build testing +build +dist +*.egg-info + + +## development tools +# pycharm +.idea +# visual studio code +.vscode + # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. diff --git a/LICENSE b/LICENSE index 8d708ff..55413f1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,28 +1,21 @@ -Copyright (c) 2018, University of California and The National Institues of Health. All rights reserved. +Copyright (c) 2018, University of California and The National Institutes of Health. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * The name of the University of California may not be used to - endorse or promote products derived from this software without - specific prior written permission. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS -IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. -For portions of this code, copyright and license information differs from -the above. In these cases, copyright and/or license information is inline. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/README.rst b/README.rst index 24c1d70..d148a0c 100644 --- a/README.rst +++ b/README.rst @@ -1,15 +1,15 @@ BIFS Module Repository -======================== +====================== This project is an implementation of Bayesian imaging in Fourier Space (BIFS). For details on the method see, e.g.: -J. Kornak, K. Young, N. Schuff, A. Du, A. A. Maudsley, M. W. Weiner. + - J. Kornak, K. Young, N. Schuff, A. Du, A. A. Maudsley, M. W. Weiner. K-Bayes Reconstruction for Perfusion MRI I: Concepts and Application. Journal of Digital Imaging. (2009) Feb 10 -J. Kornak, K. Young. + - J. Kornak, K. Young. K-Bayes Reconstruction for Perfusion MRI II: Modeling Motivation and Technical Development. Journal of Digital Imaging. (2009) Mar 10 -J. Kornak , K. Young, B.J. Soher, A.A. Maudsley. + - J. Kornak , K. Young, B.J. Soher, A.A. Maudsley. Bayesian k -space-time reconstruction of MR spectroscopic imaging for enhanced resolution. IEEE Trans Med Imaging. 2010 Jul;29(7):1333-50. The basic idea is to perform something like a Bayesian image @@ -19,6 +19,7 @@ efficient way by transforming to a space in which the degrees of freedom can, at least approximately, be treated independently. For a large class of images, transforming to a Fourier space representation appears to accomplish this quite well. + And to emphasize a point that sometimes arises as a point of confusion regarding this method, the goal is NOT to find a transform that results in a parsimonious representation of the image, but one @@ -41,14 +42,18 @@ Python, e.g. Enthought's Canopy environment). The currently required packages are (BIFS is known to work with the following versions but will typically work with many earlier versions as well): -Python 3 -numpy 1.15.4-2 -scipy 1.2.1-1 -matplotlib 2.2.4-2 -imageio 2.4.1 -jsonpickle 1.2 -pyqt5 5.7.1-1 (note: some version of PyQT 5 is required, i.e. - (the package will not work with PyQT 4) + +:: + + Python 3 + numpy 1.15.4-2 + scipy 1.2.1-1 + matplotlib 2.2.4-2 + imageio 2.4.1 + jsonpickle 1.2 + pyqt5 5.7.1-1 + (note: some version of PyQT 5 is required, i.e. + the package will not work with PyQT 4) Using the Package @@ -70,10 +75,10 @@ py -3 bifs_gui.py This provides the easiest access to the BIFS package but provides limited access to BIFS class variables. -To gain full access to the capabilities of BIFS one can: 1) run python, -2) load the BIFS class (import bifs), and 3) e.g. modify the -commands in one of the scripts (e.g. bifs_cl_2D.py) described below -to suit one's particular project. +To gain full access to the capabilities of BIFS one can: + 1) run python + 2) load the BIFS class (import bifs) + 3) e.g. modify the commands in one of the scripts (e.g. bifs_cl_2D.py) described below to suit one's particular project. Empirical Priors ~~~~~~~~~~~~~~~~ @@ -148,6 +153,8 @@ provided with the package (and mentioned above). Class variables available to constructor: +:: + init_image - initial loaded image k_image - initial k-space image mod_image - initial modulus image in k-space @@ -161,27 +168,30 @@ Class variables available to constructor: image_file_loaded - whether an image is loaded (True,False) initial_image_file_name - file name of initial image + imdim - int image dimension (1,2 or 3) imdim1 - int specifying size of 1st dimension of image imdim2 - int specifying size of 2nd dimension of image imdim3 - int specifying size of possible 3rd dimension of "image" + kdist = distance function on the shifted k-space lattice - view3Dslice - for 3D data this is a 2D array [a,b] where: - a = axis perpendicular to slice - b = fraction of maximum along that direction - for slice location + view3Dslice - for 3D data this is a 2D array [a,b] where:: + a = axis perpendicular to slice + b = fraction of maximum along that direction + for slice location prior - string specifying the prior distribution function to use current choices are: - 'Gaussian' + 'Gaussian' prior_choices - list of current prior distribution function choices (see above) prior_mean_init - prior mean before parameter space function is set up (used for tests) - prior_mean - the prior mean defined at each k-space point + prior_mean - the prior mean defined at each k-space point by the k-space parameter function + prior_std - the prior std defined at each k-space point prior_scale - the overall scale of the prior variance prior_scale_orig - prior scale at the origin - generally set huge @@ -197,15 +207,13 @@ Class variables available to constructor: bessel_approx_lims - limits for bessel approximation for rice distribution - see paper referenced in code - bessel_approx_array - array for bessel approximation for rice distribution - see paper referenced in code - + rice_denom_cutoff - cutoff for the denominator of the closed form of the posterior with a Gaussian prior and Rician likelihood derived from bessel approximation see paper referenced in code - param_func_type - string specifying the k-space BIFS parameter function to use current choices are: @@ -218,30 +226,28 @@ Class variables available to constructor: decay - float decay exponent for the inverse power parameter function bvec - 2D float array specifying intercept and amplitude for parameter space functions - banded_cutoff - cutoff for banded, inverse power k-space parameter function + banded_cutoff - cutoff for banded, inverse power k-space parameter function basis - string specifying the basis to use - currently only choice is "Fourier" - basis_choices - list of current choices (see above) bumps - dictionary containing set of "bump filters" to implement note: these "bump filters" are elements that are added - to the parameter function to increase (or decrease if the - amplitude is specified as negative) the sensitivity of the - analysis to frequency ranges known in advance to be important - (or missing) in the analyzed images. E.g. if there is a - predominance of features of a give size, adding filters at - wavelengths corresponding to that size could enhance the - sensitivity of the analysis. The scipy.signal package - provides a number of filters meant to applied in - the time (image) domain to characterize properties in the - Fourier domain. Providing these shapes for application in - the Fourier domain for BIFS was straightforward and might - be interesting to experiment with re. effective image - feature enhancement. - - + to the parameter function to increase (or decrease if the + amplitude is specified as negative) the sensitivity of the + analysis to frequency ranges known in advance to be important + (or missing) in the analyzed images. E.g. if there is a + predominance of features of a give size, adding filters at + wavelengths corresponding to that size could enhance the + sensitivity of the analysis. The scipy.signal package + provides a number of filters meant to applied in + the time (image) domain to characterize properties in the + Fourier domain. Providing these shapes for application in + the Fourier domain for BIFS was straightforward and might + be interesting to experiment with re. effective image + feature enhancement. + bump_types - set of choices for "bump" filter types to add to k-space parameter function; uses scipy.signal window types so consult that documentation for available types - @@ -257,6 +263,7 @@ Class variables available to constructor: "blackmanharris" "nuttall" "barthann" + bump_default_type - the default window type used (currently "blackman") diff --git a/bifs/__init__.py b/bifs/__init__.py deleted file mode 100644 index 0a974b1..0000000 --- a/bifs/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# from .bla import blech diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..53029b6 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,13 @@ +[metadata] +# This includes the license file(s) in the wheel. +# https://wheel.readthedocs.io/en/stable/user_guide.html#including-license-files-in-the-generated-wheel-file +license_files = 'LICENSE' + +[bdist_wheel] +# This flag says to generate wheels that support both Python 2 and Python +# 3. If your code will not run unchanged on both Python 2 and 3, you will +# need to generate separate wheels for each Python version that you +# support. Removing this line (or setting universal to 0) will prevent +# bdist_wheel from trying to make a universal wheel. For more see: +# https://packaging.python.org/guides/distributing-packages-using-setuptools/#wheels +universal=1 \ No newline at end of file diff --git a/setup.py b/setup.py index dfc19be..6afb457 100644 --- a/setup.py +++ b/setup.py @@ -8,22 +8,61 @@ with open('LICENSE') as f: license = f.read() +packages_ = find_packages('src') + setup( name='bifs', - version='0.2.0', + version='0.1.0a5', description='Implementation of Bayesian Imaging in Fourier Space (BIFS)', long_description=readme, author='John Kornak, Karl Young, Ross Boylan', - author_email='john.kornak@ucsf.edu,kyoung21b2000@gmail.com', - url='https://github.com/bifs', - license=license, - packages=['bifs'], + author_email='john.kornak@ucsf.edu', + url='https://github.com/bifs/bifs', + license='BSD', + package_dir={'': 'src'}, + package_data={'bifs': ['images/*']}, + include_package_data=True, + scripts=['src/bifs/gui/bifs_gui.py'], + entry_points = { + 'console_scripts': ['bifs_gui=bifs.gui.bifs_gui:main'], + }, + packages=packages_, + # packages=find_packages(where='src') # does not work for me. + install_requires=['imageio', 'jsonpickle', 'matplotlib', 'nibabel', 'numpy', 'PyQt5', - 'scipy'] + 'scipy'], + # Option items: + # extras_require={...}, + # data_files=[(...)], + + classifiers=[ + # How mature is this project? Common values are + # 3 - Alpha; 4 - Beta; 5 - Production/Stable + 'Development Status :: 3 - Alpha', + + # Indicate who your project is intended for + 'Intended Audience :: Developers', + 'Topic :: Scientific/Engineering', + 'Topic :: Scientific/Engineering :: Bio-Informatics', + 'Topic :: Scientific/Engineering :: Image Recognition', + + # Pick your license as you wish (should match "license" above) + 'License :: OSI Approved :: BSD License', + + # Specify the Python versions you support here. + # I assume we only support Python 3 and recent version. + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + ], + keywords='Bayesian Fourier Image development', + python_requires='>=3.5', ) diff --git a/bifs/.DS_Store b/src/bifs/.DS_Store similarity index 100% rename from bifs/.DS_Store rename to src/bifs/.DS_Store diff --git a/src/bifs/__init__.py b/src/bifs/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/bifs/__init__.py @@ -0,0 +1 @@ + diff --git a/src/bifs/bases/__init__.py b/src/bifs/bases/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bifs/src/bases/fourier.py b/src/bifs/bases/fourier.py similarity index 100% rename from bifs/src/bases/fourier.py rename to src/bifs/bases/fourier.py diff --git a/bifs/src/bifs_cl_1D.py b/src/bifs/bifs_cl_1D.py similarity index 94% rename from bifs/src/bifs_cl_1D.py rename to src/bifs/bifs_cl_1D.py index 58e651d..ceb9bd4 100644 --- a/bifs/src/bifs_cl_1D.py +++ b/src/bifs/bifs_cl_1D.py @@ -1,13 +1,10 @@ # A command line type example for using BIFS example import numpy as np -import scipy as sp -from scipy import misc,stats -import random -from pylab import * +from scipy import stats import matplotlib.pyplot as plt -import bifs -import bifs_util.util as bu +from bifs.bifs_core import Bifs +from bifs.bifs_util import util as bu # Make 1D "image" # Noise standard deviation in image space @@ -18,7 +15,7 @@ y = z + stats.norm.rvs(size=len(z),loc=0.0,scale=noiseSD) # Create mybifs BIFS object: -mybifs = bifs.bifs() +mybifs = Bifs() # Can take a look at what functions and variables are available with, e.g.: # dir(mybifs) diff --git a/bifs/src/bifs_cl_2D.py b/src/bifs/bifs_cl_2D.py similarity index 91% rename from bifs/src/bifs_cl_2D.py rename to src/bifs/bifs_cl_2D.py index 4367720..901f182 100644 --- a/bifs/src/bifs_cl_2D.py +++ b/src/bifs/bifs_cl_2D.py @@ -1,16 +1,22 @@ # A command line type example for using BIFS example +import os +import pkg_resources + import numpy as np import imageio -import random -from pylab import * +from pylab import cm import matplotlib.pyplot as plt -import bifs -import bifs_util.util as bu + +from bifs.bifs_core import Bifs +import bifs.bifs_util.util as bu # 2D image # Load image - standard Lena for now -im = imageio.imread('../../images/lena512.bmp') +path_ = 'images/lena512.bmp' # always use slash +test_2d_p2f = pkg_resources.resource_filename(__name__, path_) + +im = imageio.imread(test_2d_p2f) im = np.asarray(im) # 2D imag noise_level = 1.5 @@ -20,7 +26,7 @@ noisy_im = im + noise # Create mybifs BIFS object: -mybifs = bifs.bifs() +mybifs = Bifs() # Can take a look at what functions and variables are available with, e.g.: # dir(mybifs) @@ -105,4 +111,5 @@ plt.title("Reconstructed Image") plt.imshow(mybifs.final_image,cmap = cm.Greys_r) + plt.plot() plt.show() diff --git a/bifs/src/bifs_cl_3D.py b/src/bifs/bifs_cl_3D.py similarity index 93% rename from bifs/src/bifs_cl_3D.py rename to src/bifs/bifs_cl_3D.py index 0034a24..4c7fbf4 100644 --- a/bifs/src/bifs_cl_3D.py +++ b/src/bifs/bifs_cl_3D.py @@ -1,12 +1,15 @@ # A command line type example for using BIFS example +import os +import pkg_resources + import numpy as np import imageio -import random -from pylab import * +from pylab import cm import matplotlib.pyplot as plt -import bifs -import bifs_util.util as bu + +from bifs.bifs_core import Bifs +import bifs.bifs_util.util as bu # 3D image # Load image - sphere in 64x64x64 array @@ -24,10 +27,14 @@ # Add noise: # noisy_im = im + noise -noisy_im = imageio.imread('../../images/test3Dnoisy_sphere.tiff') +# load image +path_ = 'images/test3Dnoisy_sphere.tiff' +test_sphere_p2f = pkg_resources.resource_filename(__name__, path_) + +noisy_im = imageio.imread(test_sphere_p2f) # Create mybifs BIFS object: -mybifs = bifs.bifs() +mybifs = Bifs() # Can take a look at what functions and variables are available with, e.g.: # dir(mybifs) @@ -124,4 +131,5 @@ plt.title("Reconstructed Image") plt.imshow(fin_im_slice, cmap = cm.Greys_r) + plt.plot() plt.show() diff --git a/bifs/src/bifs.py b/src/bifs/bifs_core.py similarity index 96% rename from bifs/src/bifs.py rename to src/bifs/bifs_core.py index dbe6f21..fbb9a3e 100644 --- a/bifs/src/bifs.py +++ b/src/bifs/bifs_core.py @@ -11,16 +11,13 @@ import numpy as np import scipy as sp import matplotlib.pyplot as plt -from pylab import * -import multiprocessing as mp -from scipy import stats +from pylab import where, cm import imageio -from scipy.optimize import minimize_scalar as ms -from multiprocessing import Pool, TimeoutError from datetime import datetime import jsonpickle as jsp -class bifs: + +class Bifs: """ Class bifs for performing Bayesian image restoration in k-space @@ -62,7 +59,7 @@ class bifs: 'Gaussian' prior_choices - list of current prior choices (see above) - prior_mean_init - prior mean before paramter space function + prior_mean_init - prior mean before parameter space function is set up (used for tests) prior_mean - the prior mean defined at each k-space point by the k-space parameter function @@ -79,28 +76,28 @@ class bifs: likelihood_choices - list of current choices (see above) likelihood_scale - the assumed (const) noise level in k-space - bessel_approx_lims - limits for bessel approximtion for rice + bessel_approx_lims - limits for bessel approximation for rice distribution - see paper referenced in code - bessel_approx_array - array for bessel approximtion for rice + bessel_approx_array - array for bessel approximation for rice distribution - see paper referenced in code - rice_denom_cutoff - cutoff for the demoninator of the closed form + rice_denom_cutoff - cutoff for the denominator of the closed form of the posterior with a Gaussian prior and Rician likelihood derived from bessel approximation see paper referenced in code - param_func_type - string specifying the k-space BIFS paramter + param_func_type - string specifying the k-space BIFS parameter function to use current choices: "Inverse Power Decay" "Banded Inverse Power Decay" "Linear Decay" param_func_choices - list of current choices (see above) - decay - float decay exponent for the inverse power paramter function + decay - float decay exponent for the inverse power parameter function bvec - 2D float array specifying intercept and amplitude for parameter space functions - banded_cutoff - cutoff for banded inverse power k-space paramter function + banded_cutoff - cutoff for banded inverse power k-space parameter function basis - string specifying the basis to use - currently ony choice is "Fourier" @@ -108,7 +105,7 @@ class bifs: bumps - dictionary containing set of "bump" filters to implement bump_types - set of choices for "bump" filter types to add to k-space - paramter function; uses scipy.signal window types + parameter function; uses scipy.signal window types so consult that documentation for available types - currently only types that only require window type name and size are used - current choices are: @@ -126,7 +123,8 @@ class bifs: """ - def __init__(self,prior = "Gaussian",likelihood = "Gaussian",likelihood_scale = 0.05,prior_scale=0.0005,basis="Fourier"): + def __init__(self, prior = "Gaussian", likelihood = "Gaussian", + likelihood_scale = 0.05, prior_scale=0.0005, basis="Fourier"): """ initializes class @@ -182,7 +180,7 @@ def __init__(self,prior = "Gaussian",likelihood = "Gaussian",likelihood_scale = # For now set default parameters here; make them editable via # pop widget if self.basis == "Fourier": - import bases.fourier as fb + from bifs.bases import fourier as fb self.bas = fb self.decay = 0.5 self.param_func_type = self.bas.param_func_type @@ -201,7 +199,7 @@ def __init__(self,prior = "Gaussian",likelihood = "Gaussian",likelihood_scale = # Create an empty bump dictionary # keys are text strings for scipy.signal.window # available bump types from scipy.signal.window are - # (others like gaussian require more paramters): + # (others like gaussian require more parameters): # # Due to our use in k-space picking the preferred versions # of these, which are the versions that end at 0 @@ -285,7 +283,7 @@ def save_results(self): # Output images plt.imsave(out_im,self.final_image,cmap = cm.Greys_r) plt.imsave(out_k,np.log(out_k_im),cmap = cm.Greys_r) - # Output paramter file + # Output parameter file param_file = open(out_p, "w") param_file.write(jsp.encode(self)) param_file.close() @@ -298,7 +296,7 @@ def copy_params(self): Does not copy the image or filename """ - newbifs = bifs() + newbifs = Bifs() newbifs.param_func_type = self.param_func_type newbifs.decay = self.decay newbifs.prior = self.prior @@ -368,7 +366,7 @@ def load_image_file(self,fileName): def load_image(self,init_image): """ - intializes the bifs object so as to be ready for + initializes the bifs object so as to be ready for analysis steps. load_image_file calls this @@ -379,9 +377,9 @@ def load_image(self,init_image): load_image_file() Outputs: - sets up transformed (e.g. k-spce) data and paramter + sets up transformed (e.g. k-space) data and parameter function based on dimension and size of init_image - and default or specified paramters + and default or specified parameters """ @@ -467,10 +465,10 @@ def set_prior_from_param_func(self,pft): """ sets up k-space parameter function based on default or - specified paramters + specified parameters Inputs: - pft = paramter space function type + pft = parameter space function type Outputs: sets up k-space parameter function diff --git a/src/bifs/bifs_util/__init__.py b/src/bifs/bifs_util/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bifs/src/bifs_util/util.py b/src/bifs/bifs_util/util.py similarity index 99% rename from bifs/src/bifs_util/util.py rename to src/bifs/bifs_util/util.py index 43bddb4..f67eeff 100644 --- a/bifs/src/bifs_util/util.py +++ b/src/bifs/bifs_util/util.py @@ -8,7 +8,6 @@ import numpy as np import matplotlib.pyplot as plt -from mpl_toolkits.mplot3d import Axes3D from matplotlib import cm import scipy.stats as stats from scipy.optimize import minimize_scalar as ms diff --git a/bifs/src/bifs_gui.py b/src/bifs/gui/bifs_gui.py similarity index 94% rename from bifs/src/bifs_gui.py rename to src/bifs/gui/bifs_gui.py index 4932f17..5be2371 100644 --- a/bifs/src/bifs_gui.py +++ b/src/bifs/gui/bifs_gui.py @@ -11,23 +11,25 @@ except: newProfile = False -from PyQt5 import QtGui, QtWidgets, QtCore -from PyQt5.QtWidgets import QMessageBox +import pkg_resources +import sys +import jsonpickle +import os +import itertools + +from PyQt5 import QtWidgets, QtCore, QtGui #pyqt stuff from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure -from matplotlib.colors import NoNorm +from matplotlib.colors import NoNorm import matplotlib.pyplot as plt -from pylab import * +from pylab import cm import numpy as np -from scipy import misc -import bifs -import jsonpickle -import os -import itertools -from pset_dialogs import Param_Fourier_Space_Dialog,Prior_Dialog -from pset_dialogs import Likelihood_Dialog,Slice3D_Dialog -from pset_dialogs import AddBump_Dialog,DeleteBump_Dialog +from bifs.bifs_core import Bifs +from bifs.pset_dialogs import DeleteBump_Dialog, Prior_Dialog +from bifs.pset_dialogs import Likelihood_Dialog, Slice3D_Dialog +from bifs.pset_dialogs import AddBump_Dialog, Param_Fourier_Space_Dialog + # gastly hack # but currently if this is run in debug mode it has a different working directory than @@ -47,7 +49,7 @@ def __init__(self): super(MainWindow, self).__init__() self.main_widget = QtWidgets.QWidget(self) # Initialize BIFS object - self.mybifs = bifs.bifs() + self.mybifs = Bifs() self.filename = None self.didMAP = False self.setWindowTitle("Bayesian Imaging in Fourier Space") @@ -76,10 +78,10 @@ def __init__(self): self.show() self.update() + def getImage(self): self.getImage_real() - def getEmpiricalPrior(self): """ @@ -87,8 +89,9 @@ def getEmpiricalPrior(self): Scan each, FFT, and get mean and sd of values in k-space """ docDir = QtCore.QStandardPaths.standardLocations(QtCore.QStandardPaths.DocumentsLocation)[0] - topDirDlg = QtWidgets.QFileDialog(self, caption="Top Directory for Images", - directory = docDir) + topDirDlg = QtWidgets.QFileDialog(self, + caption="Top Directory for Images", + directory = docDir) topDirDlg.setFileMode(QtWidgets.QFileDialog.Directory) if topDirDlg.exec_(): topDir = topDirDlg.selectedFiles()[0] @@ -161,13 +164,14 @@ def _scanImages(self, rootDir): if (v1 != v2).any(): mismatch.add(key) if mismatch: - msgb = QMessageBox() + msgb = QtWidgets.QMessageBox() msgb.setText("Warning: The following keys were not uniform in the files scanned: {}.".format(mismatch)) msgb.setInformativeText("Do you want to proceed anyway?") - msgb.setStandardButtons(QMessageBox.Yes | QMessageBox.No) - msgb.setIcon(QMessageBox.Warning) - msgb.setDefaultButton(QMessageBox.No) - return msgb.exec() == QMessageBox.Yes + msgb.setStandardButtons(QtWidgets.QMessageBox.Yes | + QtWidgets.QMessageBox.No) + msgb.setIcon(QtWidgets.QMessageBox.Warning) + msgb.setDefaultButton(QtWidgets.QMessageBox.No) + return msgb.exec() == QtWidgets.QMessageBox.Yes return True def _statsAccumulate(self, m): @@ -229,10 +233,11 @@ def getImage_real(self): to load an image file. """ - # self.__init__() + path_ = '../images/' + image_path = pkg_resources.resource_filename(__name__, path_) self.fileName = QtWidgets.QFileDialog.getOpenFileName(self, "Open File", - QtCore.QDir.currentPath())[0] + image_path)[0] # Qt docs say return value is a string, but it is tuple whose first element we want try: @@ -291,6 +296,7 @@ def show_initial_image(self): self.ax1.imshow(self.mybifs.init_image,cmap = cm.Greys_r,norm=NoNorm()) else: # assume for now that the only other possibility is 3D # can change later + init_im_slice = None slice_index = np.int(np.round(self.mybifs.view3Dslice[1]*self.mybifs.init_image.shape[self.mybifs.view3Dslice[0]])) if self.mybifs.view3Dslice[0] == 0: init_im_slice = self.mybifs.init_image[slice_index,:,:] @@ -300,7 +306,8 @@ def show_initial_image(self): init_im_slice = self.mybifs.init_image[:,:,slice_index] else: print("Sorry slice index needs to be one of 0,1,2") - self.ax1.imshow(init_im_slice, cmap = cm.Greys_r) + if init_im_slice: + self.ax1.imshow(init_im_slice, cmap = cm.Greys_r) self.canvas.draw() return except: @@ -328,6 +335,7 @@ def show_post_proc_images(self): self.ax2.imshow(self.mybifs.final_image,cmap = cm.Greys_r) else: # assume for now that the only other possibility is 3D # can change later + final_im_slice = None slice_index = np.int(np.round(self.mybifs.view3Dslice[1]*self.mybifs.final_image.shape[self.mybifs.view3Dslice[0]])) if self.mybifs.view3Dslice[0] == 0: final_im_slice = self.mybifs.final_image[slice_index,:,:] @@ -337,7 +345,8 @@ def show_post_proc_images(self): final_im_slice = self.mybifs.final_image[:,:,slice_index] else: print("Sorry slice index needs to be one of 0,1,2") - self.ax2.imshow(final_im_slice, cmap = cm.Greys_r) + if final_im_slice: + self.ax2.imshow(final_im_slice, cmap = cm.Greys_r) self.canvas.draw() self.ax3.clear() @@ -351,6 +360,7 @@ def show_post_proc_images(self): self.ax3.imshow(np.log(showim1k),cmap = cm.Greys_r) else: # assume for now that the only other possibility is 3D # can change later + init_mod_im_slice = None slice_index = np.int(np.round(self.mybifs.view3Dslice[1]*self.mybifs.mod_image.shape[self.mybifs.view3Dslice[0]])) if self.mybifs.view3Dslice[0] == 0: init_mod_im_slice = self.mybifs.mod_image[slice_index,:,:] @@ -360,9 +370,9 @@ def show_post_proc_images(self): init_mod_im_slice = self.mybifs.mod_image[:,:,slice_index] else: print("Sorry slice index needs to be one of 0,1,2") - - showim1k = np.roll(np.roll(init_mod_im_slice,init_mod_im_slice.shape[0]//2,0),init_mod_im_slice.shape[1]//2,1) - self.ax3.imshow(np.log(showim1k), cmap = cm.Greys_r) + if init_mod_im_slice: + showim1k = np.roll(np.roll(init_mod_im_slice,init_mod_im_slice.shape[0]//2,0),init_mod_im_slice.shape[1]//2,1) + self.ax3.imshow(np.log(showim1k), cmap=cm.Greys_r) self.canvas.draw() self.ax4.clear() @@ -421,9 +431,9 @@ def loadPrevious(self): bifsj = bifs_handle.read() bifs_handle.close() self.mybifs = jsonpickle.decode(bifsj) - # Show intial image + # Show initial image self.show_initial_image() - # Show initial and post BIFS k-spage images and final image + # Show initial and post BIFS k-space images and final image self.show_post_proc_images() else: QtWidgets.QMessageBox.information(self, "Parameter File Loader","Cannot load %s., doesn't look like a bifs parameter file" % fileName) @@ -631,6 +641,7 @@ def getFunc(self): except: print("Couldn't get parameter function") + class StartPrior_Dialog(QtWidgets.QDialog, Prior_Dialog): def __init__(self,parent=MainWindow): QtWidgets.QDialog.__init__(self,parent) @@ -647,7 +658,8 @@ def getDist(self): return str(self.priorBox.currentText()) except: print("Couldn't get prior distribution") - + + class StartLikelihood_Dialog(QtWidgets.QDialog, Likelihood_Dialog): def __init__(self,parent=MainWindow): QtWidgets.QDialog.__init__(self,parent) @@ -665,6 +677,7 @@ def getDist(self): except: print("Couldn't get likelihood distribution") + class Start3DSlice_Dialog(QtWidgets.QDialog, Slice3D_Dialog): def __init__(self,parent=MainWindow): QtWidgets.QDialog.__init__(self,parent) @@ -685,6 +698,7 @@ def getSlicePercent(self): except: print("Couldn't get slice percent") + class StartAddBump_Dialog(QtWidgets.QDialog, AddBump_Dialog): def __init__(self,parent=MainWindow): QtWidgets.QDialog.__init__(self,parent) @@ -713,7 +727,8 @@ def getWidth(self): return np.float(QtWidgets.QLineEdit.text(self.Width)) except: print("Couldn't get bump width") - + + class StartDeleteBump_Dialog(QtWidgets.QDialog, DeleteBump_Dialog): def __init__(self,parent=MainWindow): QtWidgets.QDialog.__init__(self,parent) @@ -725,7 +740,12 @@ def getDeleteString(self): except: print("Couldn't get bump function information") -if __name__ == '__main__': + +def main(): app = QtWidgets.QApplication(sys.argv) win = MainWindow() sys.exit(app.exec_()) + + +if __name__ == '__main__': + main() diff --git a/images/kinda_noisy_lena512.bmp b/src/bifs/images/kinda_noisy_lena512.bmp similarity index 100% rename from images/kinda_noisy_lena512.bmp rename to src/bifs/images/kinda_noisy_lena512.bmp diff --git a/images/lena512.bmp b/src/bifs/images/lena512.bmp similarity index 100% rename from images/lena512.bmp rename to src/bifs/images/lena512.bmp diff --git a/images/my1dfunc.txt b/src/bifs/images/my1dfunc.txt similarity index 100% rename from images/my1dfunc.txt rename to src/bifs/images/my1dfunc.txt diff --git a/images/test3Dnoisy_sphere.tiff b/src/bifs/images/test3Dnoisy_sphere.tiff similarity index 100% rename from images/test3Dnoisy_sphere.tiff rename to src/bifs/images/test3Dnoisy_sphere.tiff diff --git a/bifs/src/pset_dialogs.py b/src/bifs/pset_dialogs.py similarity index 100% rename from bifs/src/pset_dialogs.py rename to src/bifs/pset_dialogs.py