efficient way of performing integral on an image

2019-05-28 09:33发布

I have a 2D array (typical size about 400x100) as shown (it looks like a trapezium because elements in the lower right are nan). For each element in the array, I want to perform a numerical integral along the column for several elements (of the order of ~10 elements). In physics language think of the colour as the magnitude of the force, and I want to find the work done by calculating th integral of Fdz. I can use a double for-loop and use trap to do the job, but are there other more efficient ways (probably mkaing use of arrays and vectorization) to do it in Matlab or python? My ultimate goal is to find the point where the evaluated integral is the largest. So from the image in which yellow represents large value, we expect the integral to be the largest somewhere on the right side above the dotted line.

Also, it is relatively easy if the number of points I want to integrate is an integer, but what if I want to integrate, say, 7.5 points? I am thinking of using fit to interpolate the points, but I'm not sure if that's over-complicating the task.

enter image description here

1条回答
【Aperson】
2楼-- · 2019-05-28 10:00

You can use cumsum to speedup trap. Calculating the cummulative sum (1-dimensional integral images proposed by @Benjamin)

>>> import numpy as np
>>> csdata = np.cumsum(data, axis=1)

Integrate with a discrete length

>>> npoints = 6
>>> result = np.zeros_like(data)
>>> result[:-npoints, :]  = csdata[npoints:, :] - csdata[:-npoints, :]

The result is a vectorization of cumdata[i+npoints, j] - cumdata[i, j] for every i, j in the image. It will fill with zeros last npoints rows. You can reflect the boundary with np.pad if you want to prevent this.

For non-discrete intervals, you can work with interpolations:

>>> from scipy.interpolate import interp2d
>>> C = 0.5   # to interpolate every npoints+C pixels
>>> y, x = np.mgrid[:data.shape[0], :data.shape[1]]
>>> ynew, xnew = np.mgrid[C:data.shape[0]+C, :data.shape[1]]
>>> f = interp2d(x, y, csdata)
>>> csnew = f(xnew, ynew)

The above shifts a regular grid C pixels in y direction, and interpolates the cummulative data csdata at those points (in practice, it vectorices interpolation for every pixel).

Then the integral of npoints+C length can be obtained as

>>> npoints = 6
>>> result = np.zeros_like(data)
>>> result[:-npoints, :]  = csnew[npoints:, :] - csdata[:-npoints, :]

Note that the upper bound is now csnew (a shift of 6 actually gets the 6.5 element), making it integrate every 6.5 points in practice.

You can then find the maximum point as

>>> idx = np.argmax(result.ravel()) # ravel to get the 1D maximum point
>>> maxy, maxx = np.unravel_index(idx, data.shape) # get 2D coordinates of idx
查看更多
登录 后发表回答