diff --git a/.travis.yml b/.travis.yml index 40a85ed..bb62057 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,9 +8,8 @@ branches: - v* python: -- 2.7 # - 3.4 Not in travis repositories -- 3.5 +#- 3.5 Not in travis repositories - 3.6 - 3.7 diff --git a/aotools/functions/_functions.py b/aotools/functions/_functions.py index 99731f1..f5e4101 100644 --- a/aotools/functions/_functions.py +++ b/aotools/functions/_functions.py @@ -1,6 +1,4 @@ import numpy -from . import pupil -import warnings def gaussian2d(size, width, amplitude=1., cent=None): @@ -40,84 +38,4 @@ def gaussian2d(size, width, amplitude=1., cent=None): image = amplitude * numpy.exp( -(((xCent - X) / xWidth) ** 2 + ((yCent - Y) / yWidth) ** 2) / 2) - return image - - -def aziAvg(data): - """ - Measure the azimuthal average of a 2d array - - Args: - data (ndarray): A 2-d array of data - - Returns: - ndarray: A 1-d vector of the azimuthal average - """ - warnings.warn("This function will be removed in version 0.5, instead use aotools.image_processing.azimuthal_average", - DeprecationWarning) - - size = data.shape[0] - avg = numpy.empty(int(size / 2), dtype="float") - for i in range(int(size / 2)): - ring = pupil.circle(i + 1, size) - pupil.circle(i, size) - avg[i] = (ring * data).sum() / (ring.sum()) - - return avg - - -def encircledEnergy(data, - fraction=0.5, center=None, - eeDiameter=True): - """ - Return the encircled energy diameter for a given fraction - (default is ee50d). - Can also return the encircled energy function. - Translated and extended from YAO. - - Parameters: - data : 2-d array - fraction : energy fraction for diameter calculation - default = 0.5 - center : default = center of image - eeDiameter : toggle option for return. - If False returns two vectors: (x, ee(x)) - Default = True - Returns: - Encircled energy diameter - or - 2 vectors: diameters and encircled energies - - """ - warnings.warn( - "This function will be removed in version 0.5, instead use aotools.image_processing.encircled_energy", - DeprecationWarning) - - dim = data.shape[0] // 2 - if center is None: - center = [dim, dim] - xc = center[0] - yc = center[1] - e = 1.9 - npt = 20 - rad = numpy.linspace(0, dim**(1. / e), npt)**e - ee = numpy.empty(rad.shape) - - for i in range(npt): - pup = pupil.circle(rad[i], - int(dim) * 2, - circle_centre=(xc, yc), - origin='corner') - rad[i] = numpy.sqrt(numpy.sum(pup) * 4 / numpy.pi) # diameter - ee[i] = numpy.sum(pup * data) - - rad = numpy.append(0, rad) - ee = numpy.append(0, ee) - ee /= numpy.sum(data) - xi = numpy.linspace(0, dim, int(4 * dim)) - yi = numpy.interp(xi, rad, ee) - - if eeDiameter is False: - return xi, yi - else: - ee50d = float(xi[numpy.argmin(numpy.abs(yi - fraction))]) - return ee50d + return image \ No newline at end of file diff --git a/aotools/functions/zernike.py b/aotools/functions/zernike.py index 6dc0582..9104ff8 100644 --- a/aotools/functions/zernike.py +++ b/aotools/functions/zernike.py @@ -28,7 +28,7 @@ def phaseFromZernikes(zCoeffs, size, norm="noll"): return phase -def zernike(j, N): +def zernike_noll(j, N): """ Creates the Zernike polynomial with mode index j, where j = 1 corresponds to piston. @@ -143,7 +143,7 @@ def zernikeArray(J, N, norm="noll"): nJ = len(J) Zs = numpy.empty((nJ, N, N)) for i in xrange(nJ): - Zs[i] = zernike(J[i], N) + Zs[i] = zernike_noll(J[i], N) # Else, cast to int and create up to that number except TypeError: @@ -154,7 +154,7 @@ def zernikeArray(J, N, norm="noll"): Zs = numpy.empty((maxJ, N, N)) for j in xrange(1, maxJ+1): - Zs[j-1] = zernike(j, N) + Zs[j-1] = zernike_noll(j, N) if norm=="p2v": diff --git a/aotools/image_processing/__init__.py b/aotools/image_processing/__init__.py index c359d85..b539dd0 100644 --- a/aotools/image_processing/__init__.py +++ b/aotools/image_processing/__init__.py @@ -1,4 +1,3 @@ from .centroiders import * -from ._image_processing import * from .contrast import * from .psf import * \ No newline at end of file diff --git a/aotools/image_processing/_image_processing.py b/aotools/image_processing/_image_processing.py deleted file mode 100644 index f44c804..0000000 --- a/aotools/image_processing/_image_processing.py +++ /dev/null @@ -1,43 +0,0 @@ -import warnings -import numpy -from .. import functions - - -def r0fromSlopes(slopes, wavelength, subapDiam): - """ - Measures the value of R0 from a set of WFS slopes. - - Uses the equation in Saint Jaques, 1998, PhD Thesis, Appendix A to calculate the value of atmospheric seeing parameter, r0, that would result in the variance of the given slopes. - - Parameters: - slopes (ndarray): A 3-d set of slopes in radians, of shape (dimension, nSubaps, nFrames) - wavelength (float): The wavelegnth of the light observed - subapDiam (float) The diameter of each sub-aperture - - Returns: - float: An estimate of r0 for that dataset. - - """ - warnings.warn("This function will be removed in version 0.5, instead use aotools.turbulence.r0_from_slopes", DeprecationWarning) - - slopeVar = slopes.var(axis=(-1)) - - r0 = ((0.162 * (wavelength ** 2) * subapDiam ** (-1. / 3)) / slopeVar) ** (3. / 5) - - r0 = float(r0.mean()) - - return r0 - - -def slopeVarfromR0(r0, wavelength, subapDiam): - """Returns the expected slope variance for a given r0 ValueError - - Uses the equation in Saint Jaques, 1998, PhD Thesis, Appendix A to calculate the slope variance resulting from a value of r0. - - """ - warnings.warn("This function will be removed in version 0.5, instead use aotools.turbulence.slope_variance_from_r0", - DeprecationWarning) - - slope_var = 0.162 * (wavelength ** 2) * r0 ** (-5. / 3) * subapDiam ** (-1. / 3) - - return slope_var diff --git a/aotools/image_processing/centroiders.py b/aotools/image_processing/centroiders.py index 035ba75..48bad26 100644 --- a/aotools/image_processing/centroiders.py +++ b/aotools/image_processing/centroiders.py @@ -41,7 +41,7 @@ def correlation_centroid(im, ref, threshold=0., padding=1): # Correlate frame with reference image corr = cross_correlate(im[frame], ref, padding=padding) - cx, cy = centreOfGravity(corr, threshold=threshold) + cx, cy = centre_of_gravity(corr, threshold=threshold) cy -= float(ny) / 2. * (float(padding) - 1) cx -= float(nx) / 2. * (float(padding) - 1) @@ -51,20 +51,16 @@ def correlation_centroid(im, ref, threshold=0., padding=1): return centroids -def centreOfGravity(img, threshold=0, minThreshold=0, **kwargs): +def centre_of_gravity(img, threshold=0, min_threshold=0, **kwargs): """ Centroids an image, or an array of images. Centroids over the last 2 dimensions. Sets all values under "threshold*max_value" to zero before centroiding Origin at 0,0 index of img. - The value under which pixels are set to 0 - is max(threshold*max_value, minThreshold) - Parameters: img (ndarray): ([n, ]y, x) 2d or greater rank array of imgs to centroid threshold (float): Percentage of max value under which pixels set to 0 - minThreshold (float): Absolute max value under which pixels set to 0 Returns: ndarray: Array of centroid values (2[, n]) @@ -73,10 +69,10 @@ def centreOfGravity(img, threshold=0, minThreshold=0, **kwargs): if threshold != 0: if len(img.shape) == 2: - thres = numpy.max((threshold*img.max(), minThreshold)) + thres = numpy.max((threshold*img.max(), min_threshold)) img = numpy.where(img > thres, img - thres, 0) else: - thres = numpy.maximum(threshold*img.max(-1).max(-1), [minThreshold]*img.shape[0]) + thres = numpy.maximum(threshold*img.max(-1).max(-1), [min_threshold]*img.shape[0]) img_temp = (img.T - thres).T zero_coords = numpy.where(img_temp < 0) img[zero_coords] = 0 @@ -94,7 +90,7 @@ def centreOfGravity(img, threshold=0, minThreshold=0, **kwargs): return numpy.array([x_centroid, y_centroid]) -def brightestPxl(img, threshold, **kwargs): +def brightest_pixel(img, threshold, **kwargs): """ Centroids using brightest Pixel Algorithm (A. G. Basden et al, MNRAS, 2011) @@ -124,7 +120,7 @@ def brightestPxl(img, threshold, **kwargs): img[:] = (img.T - pxlValues).T img = img.clip(0, img.max(), out=img) - return centreOfGravity(img) + return centre_of_gravity(img) def cross_correlate(x, y, padding=1): diff --git a/aotools/turbulence/slopecovariance.py b/aotools/turbulence/slopecovariance.py index 53bd793..c231088 100644 --- a/aotools/turbulence/slopecovariance.py +++ b/aotools/turbulence/slopecovariance.py @@ -15,13 +15,11 @@ """ -import time import multiprocessing import numpy import scipy.special -from ..functions import circle class CovarianceMatrix(object): """ diff --git a/appveyor.yml b/appveyor.yml index 1d6b9ae..90c7135 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,12 +2,15 @@ build: false environment: matrix: - - PYTHON_VERSION: 2.7 - MINICONDA: C:\Miniconda-x64 - - PYTHON_VERSION: 3.5 MINICONDA: C:\Miniconda35-x64 + - PYTHON_VERSION: 3.6 + MINICONDA: C:\Miniconda36-x64 + + - PYTHON_VERSION: 3.7 + MINICONDA: C:\Miniconda37-x64 + branches: only: diff --git a/doc/source/conf.py b/doc/source/conf.py index 2f013f2..00825f5 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -80,17 +80,20 @@ def __getattr__(cls, name): # General information about the project. project = u'AOtools' -copyright = u'2016, Centre for Advanced Instrumentation' -author = u'Centre for Advanced Instrumentation' +copyright = u'2019, The Authors' +author = u'AOtools' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = u'0.1' +full_version = aotools.__version__ +version_parts = full_version.split('.') +print(version_parts) +version = u'0.5' # The full version, including alpha/beta/rc tags. -release = u'0.1.0' +release = aotools.__version__ # '0.1.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/test/test_centroiders.py b/test/test_centroiders.py index 0278cab..7160f48 100644 --- a/test/test_centroiders.py +++ b/test/test_centroiders.py @@ -3,33 +3,33 @@ from nose.tools import raises -def test_centreOfGravity_single(): +def test_centre_of_gravity_single(): img = numpy.random.random((10, 10)) - com = image_processing.centreOfGravity(img, 0.1) + com = image_processing.centre_of_gravity(img, 0.1) assert(com.shape[0]) == 2 -def test_centreOfGravity_many(): +def test_centre_of_gravity_many(): img = numpy.random.random((5, 10, 10)) - com = image_processing.centreOfGravity(img, 0.1) + com = image_processing.centre_of_gravity(img, 0.1) assert(com.shape[0] == 2) assert(com.shape[1] == 5) -def test_centreOfGravity_value(): +def test_centre_of_gravity_value(): img = numpy.zeros((1, 5, 5)) img[0, 1:3, 2:4] = 1. - centroid = image_processing.centreOfGravity(img) + centroid = image_processing.centre_of_gravity(img) numpy.testing.assert_almost_equal(centroid, numpy.array([[2.5], [1.5]])) -def test_brightestPxl_single(): +def test_brightest_pixel_single(): img = numpy.random.random((10, 10)) - com = image_processing.brightestPxl(img, 0.3) + com = image_processing.brightest_pixel(img, 0.3) assert(com.shape[0] == 2) def test_brightestPxl_many(): img = numpy.random.random((5, 10, 10)) - com = image_processing.brightestPxl(img, 0.1) + com = image_processing.brightest_pixel(img, 0.1) assert(com.shape[0] == 2) assert(com.shape[1] == 5) diff --git a/test/test_functions.py b/test/test_functions.py index dc79565..388c817 100644 --- a/test/test_functions.py +++ b/test/test_functions.py @@ -11,26 +11,3 @@ def test_gaussian2d_2d(): gaussian = functions.gaussian2d((10, 8), (3, 2), 10., (4, 3)) print(gaussian.shape) assert gaussian.shape == (10, 8) - - -def test_encircledEnergy(): - data = numpy.random.rand(32, 32) - ee50d = functions.encircledEnergy(data) - print(ee50d) - assert type(ee50d) == float - - -def test_encircledEnergy_func(): - data = numpy.random.rand(32, 32) - x, y = functions.encircledEnergy(data, eeDiameter=False) - print(y.min(), y.max()) - assert len(x) == len(y) - assert numpy.max(y) <= 1 - assert numpy.min(y) >= 0 - - -def test_aziAvg(): - data = numpy.random.rand(32, 32) - azi = functions.aziAvg(data) - print(azi.shape) - assert azi.shape == (16,) diff --git a/test/test_image_processing.py b/test/test_image_processing.py index cdecf39..bcc083e 100644 --- a/test/test_image_processing.py +++ b/test/test_image_processing.py @@ -2,22 +2,6 @@ import numpy -def test_r0fromSlopes(): - slopes = numpy.random.random((2, 100, 2)) - wavelength = 500e-9 - subapDiam = 0.5 - r0 = image_processing.r0fromSlopes(slopes, wavelength, subapDiam) - print(type(r0)) - - -def test_slopeVarfromR0(): - r0 = 0.1 - wavelength = 500e-9 - subapDiam = 0.5 - variance = image_processing.slopeVarfromR0(r0, wavelength, subapDiam) - assert type(variance) == float - - def test_image_contrast(): image = numpy.random.random((20, 20)) contrast = image_processing.image_contrast(image) @@ -51,3 +35,26 @@ def test_azimuthal_average(): azi = image_processing.azimuthal_average(data) print(azi.shape) assert azi.shape == (16,) + + +def test_encircledEnergy(): + data = numpy.random.rand(32, 32) + ee50d = image_processing.encircled_energy(data) + print(ee50d) + assert type(ee50d) == float + + +def test_encircledEnergy_func(): + data = numpy.random.rand(32, 32) + x, y = image_processing.encircled_energy(data, eeDiameter=False) + print(y.min(), y.max()) + assert len(x) == len(y) + assert numpy.max(y) <= 1 + assert numpy.min(y) >= 0 + + +def test_aziAvg(): + data = numpy.random.rand(32, 32) + azi = image_processing.azimuthal_average(data) + print(azi.shape) + assert azi.shape == (16,) \ No newline at end of file diff --git a/test/test_turbulence.py b/test/test_turbulence.py new file mode 100644 index 0000000..16d03e4 --- /dev/null +++ b/test/test_turbulence.py @@ -0,0 +1,18 @@ +from aotools import turbulence +import numpy + + +def test_r0fromSlopes(): + slopes = numpy.random.random((2, 100, 2)) + wavelength = 500e-9 + subapDiam = 0.5 + r0 = turbulence.r0_from_slopes(slopes, wavelength, subapDiam) + print(type(r0)) + + +def test_slopeVarfromR0(): + r0 = 0.1 + wavelength = 500e-9 + subapDiam = 0.5 + variance = turbulence.slope_variance_from_r0(r0, wavelength, subapDiam) + assert type(variance) == float diff --git a/test/test_zernike.py b/test/test_zernike.py index 85e3b7e..c236acb 100644 --- a/test/test_zernike.py +++ b/test/test_zernike.py @@ -32,7 +32,7 @@ def test_zernike_nm(): def test_zernike(): - zernike_array = functions.zernike(9, 32) + zernike_array = functions.zernike_noll(9, 32) assert(zernike_array.shape == (32, 32))