2D Integration over a flattened Array - python

I'm hoping to find a way around the solution offered here to use 2D arrays in order to do 2D numerical integration.
import numpy as np
ksize = 50
a = 1.0
kdom = np.pi / a
x = np.linspace(- kdom, kdom, ksize)
y = np.linspace(- kdom, kdom, ksize)
dk = x[1]-x[0]
X,Y = np.meshgrid(x,y)
eigval = np.cos(X)+np.cos(Y)
eigvalflat = eigval.flatten()
intval = np.trapz(np.trapz(eigval,x),y)
sumval = np.sum(eigvalflat)*dk/ksize
print(intval,sumval)
Given my dummy example above, I'd like to find a way to properly integrate the 1D array (eigvalflat) while still as a flattened array even though it is a double integral.

Computationally, if the integrand is not separable, then the answer is that you can't recast the double integral as a single integral, unless you compute the integral one dimension at a time, which is what the assignment to intval is essentially doing.
Analytically, you'll have a better chance by asking yourself the question: given the 2d region of the integral (a rectangle in your example), can one find an integral over the boundary of that region? For that, Green's theorem has you covered with necessary and sufficient conditions.

Related

Difference between scipy.ndimage.gaussian_gradient_magnitude & gaussian_filter function

Anyone know what's the difference between scipy.ndimage.gaussian_gradient_magnitude [1] and scipy.ndimage.gaussian_filter[2] function?
I imagine that gaussian_gradient_magnitude(img, 1) & gaussian_filter(img, sigma= 1, order = 1) should return same results, but this is just not the case.
Thanks.
scipy.ndimage.gaussian_gradient_magnitude computes the magnitude of the gradient, which is the vector containing the partial derivatives along each axis. scipy.ndimage.gaussian_filter can compute those partial derivatives.
For a 2D image (img is a 2D NumPy array),
gm = scipy.ndimage.gaussian_gradient_magnitude(img, 1)
is the same as
dx = scipy.ndimage.gaussian_filter(img, sigma= 1, order = (0,1))
dy = scipy.ndimage.gaussian_filter(img, sigma= 1, order = (1,0))
gm = numpy.sqrt(dx**2 + dy**2)
But note that both alternatives above only produce correct results if the array is a floating-point type (ndimage fails to properly promote the type of the output array to contain the values it computes; in particular, derivatives can have negative values, so the partial derivative images must be of a signed type to make sense).

Doubling input array when using numpy for fast fourier transforms

I wrote a function that returns the real component of the fast four transform of a grid.
def take_FFT(x):
# some arbitrary field for a 1D grid
y = abs(1.0/x)
# compute FFT (in general multi-dimensional) array of real numbers
y_k = np.fft.rfftn(y)
#compute the inverse FFT
y_invk = np.fft.irfftn(y_k)
return y,y_k, y_invk # return fourier transform and inv transform
# initialize sample x
x_test = np.arange(-5,5,0.001)
field,FFT_test, inv_test = take_FFT(x_test)
How do I make an appropriate new "x array" to plot against the FFT? It is not clear to me how to make an array of length = (n/2)+1, like the one that np.fft.irfftn returns
Welcome to StackOverflow, #Messier!
If I understand your question correctly, you want to slice a numpy.array.
Suppose we have a numpy.array arr that has length N. Then to slice up to length M (such that M<=N) or up to (N/2)+1:
sliced_arr = arr[:M]
slice_half = arr[:N//2+1]
where in python versions 3 or greater, N//2 does integer division.
The easiest way to get an array of frequencies to be used with np.fft.rfft is to make use of the convenient helper function np.fft.rfftfreq:
freqs = np.rfftfreq(x_test)
The multi-dimentional equivalent for np.fft.rfftn is slightly more complicated. You will need to get the frequencies along each axes, then use np.meshgrid:
per_axis_freq = [np.fft.fftfreq(N) for N in x_test.shape[0:-1]]
per_axis_freq.append(np.fft.rfftfreq(x_test.shape[-1]))
freqs = np.meshgrid(*per_axis_freq[::-1])

Reshaping numpy array

What I am trying to do is take a numpy array representing 3D image data and calculate the hessian matrix for every voxel. My input is a matrix of shape (Z,X,Y) and I can easily take a slice along z and retrieve a single original image.
gx, gy, gz = np.gradient(imgs)
gxx, gxy, gxz = np.gradient(gx)
gyx, gyy, gyz = np.gradient(gy)
gzx, gzy, gzz = np.gradient(gz)
And I can access the hessian for an individual voxel as follows:
x = 100
y = 100
z = 63
H = [[gxx[z][x][y], gxy[z][x][y], gxz[z][x][y]],
[gyx[z][x][y], gyy[z][x][y], gyz[z][x][y]],
[gzx[z][x][y], gzy[z][x][y], gzz[z][x][y]]]
But this is cumbersome and I can't easily slice the data.
I have tried using reshape as follows
H = H.reshape(Z, X, Y, 3, 3)
But when I test this by retrieving the hessian for a specific voxel the, the value returned from the reshaped array is completely different than the original array.
I think I could use zip somehow but I have only been able to find that for making lists of tuples.
Bonus: If there's a faster way to accomplish this please let me know, I essentially need to calculate the three eigenvalues of the hessian matrix for every voxel in the 3D data set. Calculating the hessian values is really fast but finding the eigenvalues for a single 2D image slice takes about 20 seconds. Are there any GPUs or tensor flow accelerated libraries for image processing?
We can use a list comprehension to get the hessians -
H_all = np.array([np.gradient(i) for i in np.gradient(imgs)]).transpose(2,3,4,0,1)
Just to give it a bit of explanation : [np.gradient(i) for i in np.gradient(imgs)] loops through the two levels of outputs from np.gradient calls, resulting in a (3 x 3) shaped tensor at the outer two axes. We need these two as the last two axes in the final output. So, we push those at the end with the transpose.
Thus, H_all holds all the hessians and hence we can extract our specific hessian given x,y,z, like so -
x = 100
y = 100
z = 63
H = H_all[z,y,x]

Python-Numpy: Convolution, Code optimization

in the python code I'm currently developing there is a particular function that really requires a speed optimization.
To a first approximation I would like to focus on pure python code (no C or Cython implementations).
The function generates a series of gaussian curves with varying sigma depending on the x-axis position. It takes three arguments:
x0, 1d numpy array, central values of the gaussian curves
h , 1d numpy array, heights of the gaussian curves
x , 1d numpy array, values for the definition of the total sum
My goal is to obtain the sum of all the curves in the fastest way possible (it is a sort of convolution with a gaussian curve that has a position dependent sigma).
At the moment my code is:
sigs = get_sigmas(x0) # function that returns the value of sigma at each position
all_gauss_args = -0.5*np.power((x[:, np.newaxis] - x0[np.newaxis, :]) /
sigs[np.newaxis, :], 2.0)
sum = (1.0/(np.sqrt(2 * np.pi) * sigs[np.newaxis, :])) * np.exp(all_gauss_arg) *\
h[np.newaxis, :]
sum = np.sum(sum, axis=1)
return sum
It is possible to make it faster?
Thanks in advance for the help

numpy 3D meshgrid only as a view

I have a cubic grid defined by the spacing xi,yi,zi:
xi,yi,zi = [linspace(ox,ox+s*d,s) for ox,s,d in zip(origin,size,delta)]
I also have set of scalar values W onto that grid. W.shape() == size. I'd like to use scipy's linear interpolation, which requires as input:
class scipy.interpolate.LinearNDInterpolator(points, values):
Parameters :
points : ndarray of floats, shape (npoints, ndims) Data point coordinates.
values : ndarray of float or complex, shape (npoints, ...) Data values.
How do I create a fake set of points (via magical broadcasting) from xi,yi,zi? Right now I'm creating an intermediate array to feed to the interpolation function - is there a better way?
Related Question: Numpy meshgrid in 3D. The answers in this post actually create the grid - I only want to simulate it as input to another function (pure numpy solution preferred).
>>> xi, yi, zi = [np.arange(3) for i in range(3)]
>>> xx, yy, zz = np.broadcast_arrays(xi,yi[:,np.newaxis],zi[:,np.newaxis,np.newaxis])
>>> xx.shape
(3, 3, 3)
>>> xx.strides
(0, 0, 8)
You can see it didn't create new copies since the strides are 0 in the first two dimensions.
I wrote a n dimensional version of this also:
def ndmesh(*args):
args = map(np.asarray,args)
return np.broadcast_arrays(*[x[(slice(None),)+(None,)*i] for i, x in enumerate(args)])
You can construct the necessary points array in a similar way as explained in the other answers:
xx, yy, zz = np.broadcast_arrays(xi[:,None,None], yi[None,:,None], zi[None,None,:])
points = (xx.ravel(), yy.ravel(), zz.ravel())
ip = LinearNDInterpolator(points, data.ravel())
However, if you have a regular grid, then using LinearNDInterpolator is most likely not the best choice, since it is designed for scattered data interpolation. It constructs a Delaunay triangulation of the data points, but in this case the original data has already a very regular structure that would be more efficient to make use of.
Since your grid is rectangular, you can build up the interpolation as a tensor product of three 1-D interpolations. Scipy doesn't have this built-in (so far), but it's fairly easy to do, see this thread: http://mail.scipy.org/pipermail/scipy-user/2012-June/032314.html
(use e.g. interp1d instead of pchip to get 1-D interpolation)
I do not believe there is any way you can pass something to LinearNDInterpolator short of a full copy (as there are no functions for regular grids in three dimensions too). So the only place to avoid creating full arrays would be during creation of this points array, I do not know how you do it right now, so maybe it is already efficient in this regard, but I guess its likely not worth the trouble to avoid this.
Other then np.mgrid+reshape maybe something like this might be an option (not to hard to write for n-dimensions too):
# Create broadcastest versions of xi, yi and zi
# np.broadcast_arrays does not allocate the full arrays
xi, yi, zi = np.broadcast_arrays(xi[:,None,None], yi[:,None,None], zi[:,None,None])
# then you could use .flat to fill a point array:
points = np.empty((xi.size, 3), dtype=xi.dtype)
points[:,0] = xi.flat
points[:,1] = yi.flat
points[:,2] = zi.flat
Opposed to the .repeat function, the temporary arrays created here are not larger then the original xi, etc. arrays.

Categories