Numpy, subtract fixed values from all channels in a batch of images - python

I have 4 sequences of images, each formed by 5 RGB images with shape (10x10). Everything is represented by a numpy array with shape:
batch.shape = (4, 5, 10, 10, 3)
I need to apply some normalization operations on the array, where for each image, I have to subtract a fixed value from all the pixels in each of the 3 channels (a different, fixed value for each channel). An easy way to do this is:
batch[:, :, :, :, 0] -= 0.485
batch[:, :, :, :, 1] -= 0.456
batch[:, :, :, :, 2] -= 0.406
but I was wondering if there's an even faster way to do this.

Related

Indexing an array of unknown length in Python (Numpy, PyTorch)

I have an array of shape [m, 2, m, 2, ...]. By this, I mean that it has dimensions of size m and 2 that repeat a number of times L. I would like a solution of the following that works for any given L.
Example:
For L=1 the array would be of shape [m, 2]
For L=2 the array would be of shape [m, 2, m, 2]
For L=3 the array would be of shape [m, 2, m, 2, m, 2]
And so on...
I would like to index this array, in the dims of size m, with another array indices of shape [L, N] such as to eventually obtain an array of size [N, 2, 2, ...].
For a given L (e.g. L=3), I would do the indexing as follows,
array[indices[0], :, indices[1], :, indices[2], :]
resulting in an array of shape [N, 2, 2, 2].
Is there a smart way to do the indexing for generic L?
(Hope to have made the question clear!)
Edit 1:
To give idea of behavior, an ugly solution:
def indexing(array, indices):
L = indices.shape[0]
if L == 1:
array = array[indices[0]]
elif L == 2:
array = array[indices[0], :, indices[1], :]
elif L == 3:
array = array[indices[0], :, indices[1], :, indices[2], :]
elif L == 4:
array = array[indices[0], :, indices[1], :, indices[2], :, indices[3], :]
# etc...
return array
And a use example:
import torch
m = 5
N = 4
L = 3
array = torch.randn(m, 2, m, 2, m, 2)
indices = torch.randint(m, size=(L, N))
indexing(array, indices).shape # torch.Size([4, 2, 2, 2])
You can use len()! Pretty simple usage:
length = len(array)
for i in range(0, length):
# do something
You can also access the last item of the array whatever its length is by indexing -1, like so:
array = [1, 1, 5, 2, 4, ..., 99]
print(array[-1]) # 99

Python: drop index from tensor

I have two tensors.
tensor_A corresponds to a batch of 8 images, with 20 classes of objects and each image is 256 x 256
tensor_B corresponds to 8 arrays of len 20 full of 1 or 0, corresponding to if the object class is present
tensor_A.shape = ([8, 20, 256, 256])
tensor_B.shape = ([8, 20])
from tensor_A, I want to drop indices that correspond to 1 in tensor_B
for example if tensor_B[0] = [1,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0]
I would like to do tensor_A[0, 0, :, :].drop then tensor_A[0, 2, :, :].drop and so on, but all in one step
So far i have identified the indices that correspond to 1, by using the following:
for i in range(8):
(tensor_B[i, :] == 0).nonzero())
# code for dropping here
Not sure how to proceed
What you want won't work because:
# A -> tensor of shape (8, 20, 256, 256)
# B -> tensor of shape (8, 20)
# If B[0] = [1,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0]
dropped_A_0 = A[0, B[0] == 0, :, :]
# dropped_A_0 -> tensor of shape (1, 13, 256, 256)
# If B[1] = [1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0]
dropped_A_1 = A[1, B[1] == 0, :, :]
# dropped_A_1 -> tensor of shape (1, 16, 256, 256)
You see the problem? When you "drop" values from the rows of A, they aren't the same shape any more, and thus cannot exist together as a single tensor. What you can have is a list of the rows of A with dropped values:
dropped_A = []
for i in range(len(A)):
dropped_A.append(A[i, B[i] == 0, :, :])
Another thing you can do is simply set the unneeded values in A to 0.
A[B == 1] = 0

grid with circular distances python

I have a 2d grid of dim q(rows) p(columns).
The element of the grid are the indices of the element itself.
So the element a[i,j]=(i,j).
Now I need to create pair-wise distances between these points with circularity constraint, meaning that the element distance(a[i,p-1],a[i,0])=1 (I am using 0-index based matrix as in Python). Analogously distance(a[q-1,j],a[0,j])=1
Observe that distance(a[q-2,j],a[0,j]) is the shorter vertical path going from 0 to q-2 and the path from q2 to 0 (leveraging the circularity of the grid). Same thing happens horizontally.
My question is: is there a NumPy function that enables to quickly calculate such a pairwise distances matrix?
I don't know of a function do do this, but it's pretty easy to compute manually:
import numpy as np
q = 6 # rows
p = 5 # columns
# Create array of indices
a = np.mgrid[0:q, 0:p].transpose(1, 2, 0)
# The array `a` now has shape (q, p, 2) :
a[1, 2] # array([1, 2])
a[3, 0] # array([3, 0])
# Create a new array measuring the i,j difference between all pairs of
# locations in the array. `diff` will have shape (q, p, q, p, 2) :
diff = a[None, None, :, :, :] - a[:, :, None, None, :]
# Modify diff to obey circularity constraint
di = diff[..., 0]
dj = diff[..., 1]
di[di > q//2] -= q
dj[dj > p//2] -= p
# compute distance from diff
dist = (diff[..., 0]**2 + diff[..., 1]**2)**0.5
# test:
dist[1, 0, 1, 0] # 0.0
dist[1, 0, 1, 1] # 1.0
dist[1, 0, 1, 2] # 2.0
dist[1, 0, 1, 3] # 2.0
dist[1, 0, 1, 4] # 1.0

How is a 3-d tensor indexed by two 2d tensors?

Here's a snapshot from line 15-20 in DIM
def random_permute(X):
X = X.transpose(1, 2)
b = torch.rand((X.size(0), X.size(1))).cuda()
idx = b.sort(0)[1]
adx = torch.range(0, X.size(1) - 1).long()
X = X[idx, adx[None, :]].transpose(1, 2)
return X
where X is a tensor of size [64, 64, 128], idx a tensor of size [64, 64], adx a tensor of size [64].
How does X = X[idx, adx[None, :]] work? How can we use two 2d tensors to index a 3d tensor? What really happens to X after this indexing?
From my guess X must be a 3D tensor, since it usually represents a batch of training data.
As far as the functionality of this function is concerned, it randomly permutes the input data tensor X and it does this using the following steps:
First it initializes the tensor b with values sampled from uniform distribution.
Next this tensor is sorted along dimension 0 and the sorting indices are pulled out to tensor idx.
The tensor adx is just an integer tensor of values ranging from 0 to 63.
Now, the below line is where all the magic happens:
X[idx, adx[None, :]].transpose(1, 2)
We use the indices we got before idx and adx (adx[None, :] is simply a row vector of two dimension). Once we have that, we transpose the axes 1 and 2 exactly like what we did at the beginning of the function in the line:
X = X.transpose(1, 2)
Here is a contrived example, for better understanding:
# our input tensor
In [51]: X = torch.rand(64, 64, 32)
In [52]: X = X.transpose(1, 2)
In [53]: X.shape
Out[53]: torch.Size([64, 32, 64])
In [54]: b = torch.rand((X.size(0), X.size(1)))
# sort `b` which returns a tuple and take only indices
In [55]: idx = b.sort(0)[1]
In [56]: idx.shape
Out[56]: torch.Size([64, 32])
In [57]: adx = torch.arange(0, X.size(1)).long()
In [58]: adx.shape
Out[58]: torch.Size([32])
In [59]: X[idx, adx[None, :]].transpose(1, 2).shape
Out[59]: torch.Size([64, 64, 32])
The important thing to note here is how we got the same shape in the last step as the shape of the input tensor which is (64, 64, 32).
Things will be more clear if we consider a smaller concrete example. Let
x = np.arange(8).reshape(2, 2, 2)
b = np.random.rand(2, 2)
idx = b.argsort(0) # e.g. idx=[[1, 1], [0, 0]]
adx = np.arange(2)[None, :] # [[0, 1]]
y = x[idx, adx] # implicitly expanding 'adx' to [[0, 1], [0, 1]]
In this example, we'll have y as
y[0, 0] = x[idx[0, 0], adx[0, 0]]=x[1, 0]
y[0, 1] = x[idx[0, 1], adx[0, 1]]=x[1, 1]
y[1, 0] = x[idx[1, 0], adx[1, 0]]=x[0, 0]
...
It may be helpful to see how we do the same in tensorflow:
d0, d1, d2 = x.shape.as_list()
b = np.random.rand(d0, d1)
idx = np.argsort(b, 0)
idx = idx.reshape(-1)
adx = np.arange(0, d1)
adx = np.tile(adx, d0)
y = tf.reshape(tf.gather_nd(x, zip(idx, adx)), (d0, d1, d2))

Replace regions in a raster image with values from another image in python

I have two raster images of the same area and x,y dimensions as numpy arrays. Image 1 is a land-use classification (e.g. with classes 0 to 5) and image 2 is a cloud-shadow mask (with the values: 0 = cloudfree, 255 = cloud/ shadow areas).
I want to combine those images. Either take/clip all the 255 values from image 2 and mosaic them onto image 1. OR replace all the 0 values in image 2 with the values found at the specific pixel position in image 1.
I tried to make the 2d arrays 1d and replace the 0 values but then couldn't convert it correctly back into 2d.
What would be the easiest or best way to do this raster calculation completely open-source in python???
You can do this with numpy's boolean indexing feature.
img1 = np.array([[0, 1, 0, 1],[1, 0, 1, 0]])
img2 = np.array([[1, 2, 3, 4],[5, 6, 7, 8]])
bool_arr = img1 == 0
img1[bool_arr] = img2[bool_arr]
print(img1)
# outputs: [[1 1 3 1]
# [1 6 1 8]]

Categories