I'm new to python and am far more familliar with Matlab. If my question is ill suited for this forum, don't hesitate to point it out.
I'm trying to make local averages at a very fast speed. It's like I'm trying to reduce the number of pixel in an image, by making an average of multiple pixels for each new pixel, except I'm doing it in 3D.
Imagine a 1000x1000x6 arrays. I'm dividing this array in multiple tiny arrays of 10x10x3. I then want to calculate the mean of all those tiny arrays and put them back together to build back my array.
The way I did it on Matlab was with convn(array,seed,'valid'), which is a multi-dimension convolution function.
What would be the easiest way to do it in python?
Thanks
RMT
I think the closest thing that you can find to the convn is the SciPy's convolve. Below is the example
import numpy as np
from scipy.ndimage import convolve
M = np.random.random((1000, 1000, 6))
seed = np.ones((3, 3, 3)) * 0.1 / 27.
N = convolve(M, seed, mode='constant', cval=0)
The mode='constant', cval=0 is just zero-padding.
Not sure if that's what you need, but that's a start
Doc: https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.ndimage.filters.convolve.html
Related
I did dot product of the image with a noise.
import numpy as np
np.random.seed(100)
x = grayscale.shape[0]
y = grayscale.shape[1]
noise = np.random.rand(x,y)
noise_dot_img = grayscale.dot(noise)
plt.imshow(noise_dot_img, cmap = "gray")
Image with noise
Original image
Apologies for the horrible formatting but stack overflow doesn't support latex.
The dot product between two vectors (if they are NxM matrices you can just drop the transpose since dot product between matrices is defined as matrix multiplication in numpy) A and B is A dot B = AB^T
If A is your original image and B is the noise matrix you can reverse it by multiplying your final image matrix with the inverse of B^T (if it has one), since matrix multiplication is associative.
So to get your original matrix A = A dot B * (B^T)^-1
EDIT: for clarity here is some example code:
import numpy as np
A = np.random.randint(10, size=(3, 3))
B = np.random.randint(10, size=(3, 3))
image_with_noise = A.dot(B)
noise_inverse = np.linalg.inv(B)
recreated_image = np.matmul(image_with_noise, noise_inverse)
I think you should share some more information about what exactly you are trying to achieve here.
In any case, you actually can get your image back in this specific example, by inverting the noise matrix and multiplying with it the noisy image:
inv = np.linalg.inv(noise)
restored_img = noise_dot_img#inv
However, there are a lot of things that need explaining. Overall, this is not really how we tackle this problem, since we almost never know the "noise" matrix. This is why signal processing exists. Also, in this example you are dealing with a square image. Otherwise, we would not be able to find the inverse (and we would have to use the pseudo-inverse). That said, one should always be careful before deciding to invert matrices.
The specific problem I try to solve is:
I have a binary image binary map that I want to generate a heatmap (density map) for, my idea is to get the 2D array of this image, let say it is 12x12
a = np.random.randint(20, size=(12, 12));
index and process it with a fixed-size submatrix (let say 3x3), so for every submatrix, a pixel percentage value will be calculated (nonzero pixels/total pixel).
submatrix = a[0:3, 0:3]
pixel_density = np.count_nonzero(submatrix) / submatrix.size
At the end, all the percentage values will made up a new 2D array (a smaller, 4x4 density array) that represent the density estimation of the original image. Lower resolution is fine because the data it will be compared to has a lower resolution as well.
I am not sure how to do that through numpy, especially for the indexing part. Also if there is a better way for generating heatmap like that, please let me know as well.
Thank you!
Maybe a 2-D convolution? Basically this will sweep through the a matrix with the b matrix, which is just 1s below. So it will do the summation you were looking for. This link has a visual demo of convolution near the bottom.
import numpy as np
from scipy import signal
a = np.random.randint(2, size=(12, 12))
b = np.ones((4,4))
signal.convolve2d(a,b, 'valid') / b.sum()
I have a 50 dimensional array, whose dimensions are 255 x 255 x 255 x...(50 times)..x255. So its a total of 50^255 floating point numbers. Its just out of scope to even think of fitting in a RAM. Moreover I need to take an 50 dimensional Fast Fourier Transform (DFT) of this array. I can't do it in python on an ordinary PC. I cant even imagine doing it on a GPU. so I am guessing I have to take help of a hard disk memory, but even that is too huge. I don't need this in real time, I can afford even days for it to run. I have no clue what sort of machine I need or is it even possible? Appreciate your advice. Super computers, grids, or something even if its too costly, I am not worried about investment.
If you found enough universes to save your data in, here is what you could do:
The Fourier Transform is separable, that means that calculating the DFT of each axis one after the other will give you the same result as if you calculated the n-dimensional DFT:
for i in range(C.ndim):
C[...] = numpy.fft.fft(C, axis=i)
Double checking if the value is correct using a 2D tensor (because we have a 2D FFT numpy.fft.fft2 to compare against):
import numpy
A = numpy.random.rand(*[16] * 2)
B = numpy.fft.fft2(A)
C = A.astype(numpy.complex) # output vector for separable FFT
for i in range(C.ndim):
C[...] = numpy.fft.fft(C, axis=i)
numpy.allclose(C, B) # True
I have two large grayscale images. Either PIL.Image or numpy data structure.
How do I do 1d convolution of the two images along one axis?
The best I come up with is
def conv2(im1, im2, *args):
res = 0
for l1, l2 in zip(im1, im2):
res += np.convolve(l1, l2, *args)
return res
Which works, but not extremely fast. Is there a faster way?
Please note that all the 2D convolution functions are probably not relevant since I am not interested in a 2D convolution. I've seen this question on SO before, but I didn't see a better answer than my code. So I'm bumping it again.
FFT along one axis, multiply along one axis and inverse FFT.
Should be MUCH faster according to this explanation
Scipy.signal.fftconvolve should do the job.
I'm using a function in python's opencv library to get the light flow movement of my hand as I move it around. Specifically http://docs.opencv.org/modules/video/doc/motion_analysis_and_object_tracking.html#calcopticalflowfarneback
This function outputs a numpy array
flow = cv2.calcOpticalFlowFarneback(prevgray, gray, 0.5, 3, 15, 3, 5, 1.2, 0)
print flow.shape # prints (480,320,2)
So flow is a matrix with each entry a vector. I want a way to quantify this matrix so I though of using the L1 Matrix norm (numpy.linalg.norm(flow, 1)) Which throws a improper dimensions to norm error.
I'm thinking about getting around this by calculating the euclidean norm of every vector and then finding the L1 norm of a matrix with the distances of the vectors.
I'm having trouble iterating through the flow matrix efficiently. I have done it using two for loops by going first through columns and then rows, but it's way too slow.
r,c,d = flow.shape
flowprime = numpy.zeros((r,c),flow.dtype)
for i in range(0,r):
for j in range (0,c):
flowprime[i,j] = numpy.linalg.norm(flow[i,j], 2)
print(numpy.linalg.norm(flowprime, 1))
I had also tried using numpy.nditer but
for x in numpy.nditer(flow, op_flags=['readwrite']):
print x
just prints a single value rather than a vector.
What would be the fastest way to iterate through a numpy matrix with vectors as entries, norm them and then take the L1 norm?
As of numpy version 1.9, norm takes an axis argument.
Aside from that, say what you want ideally, and almost surely you can ask numpy to do it. E.g., assuming no complex entries or missing values, the simplest case np.sqrt((flow**2).sum()) or the case I think you describe np.linalg.norm(np.sqrt((flow**2).sum(axis=-1)),1).