Circular mask numpy array in one step - python

I want to apply a circular mask to all elements in a numpy array with specific values. At the moment my (example) code looks like this:
import numpy as np
n = 14
r = 3 #radius
### example array ###
array = np.zeros((n, n))
array[2,:]=1
array[:,5]=1
array[5,:]=1
array[:,9] = 3
a, b = np.where((array == 1) | (array == 3))
print(array)
### applying mask ###
for i in range(a.size-1):
y,x = np.ogrid[-a[i]:np.size(array, 0)-a[i], -b[i]:np.size(array, 1)-b[i]]
mask = x*x + y*y <= r*r
array[(mask) & (array != 1) & (array != 3)] = 255 # setting elements in neighborhood of 1 and 3 to 255
print(array)
The code works as I want it but my real data is much bigger and the algorithm is very slow. At the moment every point/mask gets evaluated one after another (for loop). Is there a way to create a mask for all 1 and 3 (in this example) at one time?

Related

Is there a way to use numpy array functions to get this same effect?

I am trying to filter out all non-gray values within a given tolerance with the following code. It gives the expected results but runs too slowly to use in practice. Is there a way to do the following using numpy operations?
for i in range(height):
for j in range(width):
r, g, b = im_arr[i][j]
r = (r + 150) / 2
g = (g + 150) / 2
b = (b + 150) / 2
mean = (r + g + b) / 3
diffr = abs(mean - r)
diffg = abs(mean - g)
diffb = abs(mean - b)
maxdev = 2
if (diffr + diffg + diffb) > maxdev:
im_arr[i][j][0] = 0
im_arr[i][j][1] = 0
im_arr[i][j][2] = 0
Looping in plain Python is slow: one of the advantages of numpy is that
transversing the arrays is highly optimized. Without commenting on the algorithm, you can get the same results using only numpy, which will be much faster
Since im_arr is an image, it is very likely that the dtype is np.uint8.
That is only 8 bits, so you have to be careful of overflows. In you code, when you add 150 to a number, the result will be of type np.int64. But if you add 150 to an 8-bit np.ndarray, the result will still be of type np.uint8 and it can overflow.
You can either change the array type (using astype) or add a float, which will automatically promote the array to float
mod_img = (im_arr + 150.)/2 # the point of "150." is important
signed_dif = mod_img - np.mean(mod_img, axis=2, keepdims=True)
collapsed_dif = np.sum(np.abs(signed_dif), axis=2)
maxdev = 2
im_arr[collapsed_dif > maxdev] = 0
This can be done without any loop. I'll try to break out every step into a dedicated line
import numpy as np
im_arr = np.random.rand(300,400,3) # Assuming this how you image looks like
img_shifted = (im_arr + 15) / 2 # This can be done in one go
mean_v = np.mean(img_shifted, axis=2) # Compute the mean along the channel axis
diff_img = np.abs(mean_v[:,:,None] - img_shifted) # Broadcasting to subtract n x m from n x m x k
maxdev = 2
selection = np.sum(diff_img, axis=2) > maxdev
im_arr[selection] = 0 # Using fancy indexing with booleans

Compute a least square only on n best values of an array

I have :
print(self.L.T.shape)
print(self.M.T.shape)
(8, 3)
(8, 9082318)
self.N = np.linalg.lstsq(self.L.T, self.M.T, rcond=None)[0].T
which is working fine and return
(9082318, 3)
But
I want to perform a kind of sort on M and compute the solution only on the best 8 - n values of M.
Or ignore values of M below and/or higher than a certain value.
Any pointer on how to do that would be extremely appreciated.
Thank you.
Tried to copy this solution exactly but it return an error
The original working function but basically it's just one line.
M is a stack of 8 grayscale images reshaped.
L is a stack of 8 light direction vectors.
M contains shadows but not always at the same location in the image.
So I need to remove those pixel from the computation but L must retains its dimensions.
def _solve_l2(self):
"""
Lambertian Photometric stereo based on least-squares
Woodham 1980
:return: None
Compute surface normal : numpy array of surface normal (p \times 3)
"""
self.N = np.linalg.lstsq(self.L.T, M.T, rcond=None)[0].T
print(self.N.shape)
self.N = normalize(self.N, axis=1) # normalize to account for diffuse reflectance
Here is the borrowed code from the link for trying to resolve this :
L and M as previously used
Ma = self.M.copy()
thresh = 300
Ma[self.M <= thresh] = 0
Ma[self.M > thresh] = 1
Ma = Ma.T
self.M = self.M.T
self.L = self.L.T
print(self.L.shape)
print(self.M.shape)
print(Ma.shape)
A = self.L
B = self.M
M = Ma #http://alexhwilliams.info/itsneuronalblog/2018/02/26/censored-lstsq/
# else solve via tensor representation
rhs = np.dot(A.T, M * B).T[:,:,None] # n x r x 1 tensor
T = np.matmul(A.T[None,:,:], M.T[:,:,None] * A[None,:,:]) # n x r x r tensor
self.N = np.squeeze(np.linalg.solve(T, rhs)).T # transpose to get r x n
return
numpy.linalg.LinAlgError: Singular matrix

Can I do a mathematical-shape mask for a (Nx,Ny) matrix?

I have a matrix of numbers (Nx,Ny) and I would like to select from that matrix a mathematical shape coordinates/components as it could be a line with a given slope.
I learned how to create a mask and how to do it in a random way but I cannot think of how to generate a mathematical-shape mask in python.
This is some of the code that I've been able to develop. If you know a better way to do this I will be also grateful of being told.
import random
import numpy as np
threshold = 0.85
radius=40
sq7=1/(radius*radius)
matrix=np.zeros((Nx,Ny))
for i in range(0,Nx):
for j in range(0,Ny):
if ((i-Nx*0.5)*(i-Nx*0.5)*sq7+(j-Ny*0.5)*(j-Ny*0.5)*sq7<=1.0):
matrix[i,j]= 1.0 - 0.1*random.random();
else:
matrix[i,j]=-1.0 + random.random();
randoms = np.random.normal(0,scale=0.002, size=matrix[mask].shape)
mask = matrix**2 < threshold
matrix[mask] += randoms * (1 - matrix[mask]**2)
At the end I found a very easy way of doing so. What I just did was to create a new matrix of the same dimensions as the one that I want to mask and then just by going through the matrix itself and comparing with the values of my function I could do it so easily. I will leave the code here.
def func_normaldist(x,Ny):
y = np.exp(-0.5*(x-int(Ny/2))**2)/np.sqrt(np.pi*2.)
return y
def mask_uvalues_centered_geometry(Nx, Ny): #u
mask = np.zeros((Nx,Ny))
# Initial configuration: rectangle of Nx x Ny
for j in range(0,Ny):
for i in range(0,Nx):
if (i < Ny*Nx*func_normaldist(j,Ny)):# and (i > int(Nx/2 + 1)):
mask[j,i] = True
else:
mask[j,i] = False;
return mask
Nx = 50
Ny = 50
a = mask_uvalues_centered_geometry(Nx,Ny)
print(a)

generating random matrices in python

In the following code I have implemented Gaussian elimination with partial pivoting for a general square linear system Ax=b. I have tested my code and it produced the right output. However now I am trying to do the following but I am not quite sure how to code it, looking for some help with this!
I want to test my implementation by solving Ax=b where A is a random 100x100 matrix and b is a random 100x1 vector.
In my code I have put in the matrices
A = np.array([[3.,2.,-4.],[2.,3.,3.],[5.,-3.,1.]])
b = np.array([[3.],[15.],[14.]])
and gotten the following correct output:
[3. 1. 2.]
[3. 1. 2.]
but now how do I change it to generate the random matrices?
here is my code below:
import numpy as np
def GEPP(A, b, doPricing = True):
'''
Gaussian elimination with partial pivoting.
input: A is an n x n numpy matrix
b is an n x 1 numpy array
output: x is the solution of Ax=b
with the entries permuted in
accordance with the pivoting
done by the algorithm
post-condition: A and b have been modified.
'''
n = len(A)
if b.size != n:
raise ValueError("Invalid argument: incompatible sizes between"+
"A & b.", b.size, n)
# k represents the current pivot row. Since GE traverses the matrix in the
# upper right triangle, we also use k for indicating the k-th diagonal
# column index.
# Elimination
for k in range(n-1):
if doPricing:
# Pivot
maxindex = abs(A[k:,k]).argmax() + k
if A[maxindex, k] == 0:
raise ValueError("Matrix is singular.")
# Swap
if maxindex != k:
A[[k,maxindex]] = A[[maxindex, k]]
b[[k,maxindex]] = b[[maxindex, k]]
else:
if A[k, k] == 0:
raise ValueError("Pivot element is zero. Try setting doPricing to True.")
#Eliminate
for row in range(k+1, n):
multiplier = A[row,k]/A[k,k]
A[row, k:] = A[row, k:] - multiplier*A[k, k:]
b[row] = b[row] - multiplier*b[k]
# Back Substitution
x = np.zeros(n)
for k in range(n-1, -1, -1):
x[k] = (b[k] - np.dot(A[k,k+1:],x[k+1:]))/A[k,k]
return x
if __name__ == "__main__":
A = np.array([[3.,2.,-4.],[2.,3.,3.],[5.,-3.,1.]])
b = np.array([[3.],[15.],[14.]])
print (GEPP(np.copy(A), np.copy(b), doPricing = False))
print (GEPP(A,b))
You're already using numpy. Have you considered np.random.rand?
np.random.rand(m, n) will get you a random matrix with values in [0, 1). You can further process it by multiplying random values or rounding.
EDIT: Something like this
if __name__ == "__main__":
A = np.round(np.random.rand(100, 100)*10)
b = np.round(np.random.rand(100)*10)
print (GEPP(np.copy(A), np.copy(b), doPricing = False))
print (GEPP(A,b))
So I would use np.random.randint for this.
numpy.random.randint(low, high=None, size=None, dtype='l')
which outputs a size-shaped array of random integers from the appropriate distribution, or a single such random int if size not provided.
low is the lower bound of the ints you want in your range
high is one greater than the upper bound in your desired range
size is the dimensions of your output array
dtype is the dtype of the result
so if I was you I would write
A = np.random.randint(0, 11, (100, 100))
b = np.random.randint(0, 11, 100)
Basically you could create the desired matrices with ones and then iterate over them, setting each value to random.randint(0,100) for example.
Empty matrix with ones is:
one_array = np.ones((100, 100))
EDIT:
like:
for x in one_array.shape[0]:
for y in one_array.shape[1]:
one_array[x][y] = random.randint(0, 100)
A = np.random.normal(size=(100,100))
b = np.random.normal(size=(100,1))
x = np.linalg.solve(A,b)
assert max(abs(A#x - b)) < 1e-12
Clearly, you can use different distributions than normal, like uniform.
You can use numpy's native rand function:
np.random.rand()
In your code just define A and b as:
A = np.random.rand(100, 100)
b = np.random.rand(100)
This will generate 100x100 matrix and 100x1 vector (both numpy arrays) filled with random values between 0 and 1.
See the docs for this function to learn more.

Turn grid into a checkerboard pattern in python?

I have successfully created a grid, but am now trying to turn my grid into a checkerboard pattern, preferably using a variant of the floodfill command. how do I make sure the program recognizes which squares are even and which are odd?
currently the IDE is set so m[i][j]= 1 gives blue, while m[i][j]= 0 gives red, which I am happy to keep, and so I do not need to define the colors. Thank you.
Code I have so far :
from pylab import *
from numpy import *
from math import *
m=zeros((100,100))
for i in range(100):
for j in range(100):
if (math.floor(i) % 10) != 0:
if (math.floor(j) % 10) != 0:
m[i][j]= 1
else:
m[i][j]= 0
imshow(m)
show()
Code output :
import numpy as np
def make_checkerboard(n_rows, n_columns, square_size):
n_rows_, n_columns_ = int(n_rows/square_size + 1), int(n_columns/square_size + 1)
rows_grid, columns_grid = np.meshgrid(range(n_rows_), range(n_columns_), indexing='ij')
high_res_checkerboard = np.mod(rows_grid, 2) + np.mod(columns_grid, 2) == 1
square = np.ones((square_size,square_size))
checkerboard = np.kron(high_res_checkerboard, square)[:n_rows,:n_columns]
return checkerboard
square_size = 5
n_rows = 14
n_columns = 67
checkerboard = make_checkerboard(n_rows, n_columns, square_size)
You can check the sum of the two indices (row and column) and color it with the first color if it's odd and second otherwise. Something like:
for i in range(nrows):
for j in range(ncols):
m[i][j] = 0 if (i+j)%2 else 1
Use the modulus operation:
m[i][j] = (i+j) % 2
I would create a linear array, fill every second value and reshape.
In your case (even amount of columns), prepend one column and get rid of it after reshaping:
import numpy as np
rows = 100
cols = 100 + 1 # product of rows*cols must be odd, we fix it later
m = np.zeros((rows*cols, 1)) # create array
m[::2] = 1 # fill every second
m = np.reshape(m, (rows, cols)) # reshape array to matrix
m = m[:, :-1] # cut additional column
You can create a checkerboard style array with NumPy, then resize it with scipy's imresize to make that equal to your desired canvas area.
Thus, the steps would be :
1) Create a NumPy array of shape (10,10) corresponding to 10 x 10 sized checkerboard pattern. To do so, start with zeros array and fill the alternate rows and columns with ones :
arr = np.zeros((10,10),dtype=int)
arr[::2,::2] = 1
arr[1::2,1::2] = 1
2) Resize the array 10x to have (100,100) pixel sized output image :
from scipy.misc import imresize # Importing required function
out = imresize(arr,10*np.array(arr.shape),interp='nearest')/255
Output :
With only minimal modification of your code it would look something like this:
from pylab import *
from numpy import *
from math import *
m=zeros((100,100))
for i in range(100):
for j in range(100):
if (math.floor(i) % 10) != 0:
if (math.floor(j) % 10) != 0:
m[i][j]= 1
if (int(i / 10) + int(j / 10)) % 2: # the only two extra lines.
m[i][j] = 0 #
imshow(m)
show()
Alternatively just this (assuming you really need the 100x100) to get rid of the "boundary lines":
m=zeros((100,100))
for i in range(100):
for j in range(100):
m[i][j] = (int(i / 10) + int(j / 10)) % 2
Cheers.

Categories