NumPy + PyTorch Tensor assignment - python

lets assume we have a tensor representing an image of the shape (910, 270, 1) which assigned a number (some index) to each pixel with width=910 and height=270.
We also have a numpy array of size (N, 3) which maps a 3-tuple to an index.
I now want to create a new numpy array of shape (920, 270, 3) which has a 3-tuple based on the original tensor index and the mapping-3-tuple-numpy array. How do I do this assignment without for loops and other consuming iterations?
This would look simething like:
color_image = np.zeros((self._w, self._h, 3), dtype=np.int32)
self._colors = np.array(N,3) # this is already present
indexed_image = torch.tensor(920,270,1) # this is already present
#how do I assign it to this numpy array?
color_image[indexed_image.w, indexed_image.h] = self._colors[indexed_image.flatten()]

Assuming you have _colors, and indexed_image. Something that ressembles to:
>>> indexed_image = torch.randint(0, 10, (920, 270, 1))
>>> _colors = np.random.randint(0, 255, (N, 3))
A common way of converting a dense map to a RGB map is to loop over the label set:
>>> _colors = torch.FloatTensor(_colors)
>>> rgb = torch.zeros(indexed_image.shape[:-1] + (3,))
>>> for lbl in range(N):
... rgb[lbl == indexed_image[...,0]] = _colors[lbl]

Related

Python - Numpy - Get a list of numpy.random.normal values in a particular shape without using a loop

I am new to Python and curious if there is a way to instantly create a list of numpy.random.normal values of a specific shape without using a loop like this?
def get_random_normal_values():
i = 0
result = []
while i < 100:
result.append(np.random.normal(0.0, 1.0, (16, 16, 3)))
i = i + 1
return result
Simply use the size parameter to numpy.random.normal to define the final shape of the desired array:
result = np.random.normal(size=(100, 16, 16, 3)) # default parameters are loc=0.0, scale=1.0
You will get an array instead of a list of arrays, but this does not remove functionality (you can still loop over it). Please make your use case more explicit if this doesn't suit your needs.
Yes, of course it is posssible:
import numpy as np
def get_random_normal_values(n_samples: int, size: tuple[int]) -> list[np.array]:
all_samples = np.random.normal(np.random.normal(0.0, 1.0, (n_samples, ) + size))
return list(all_samples)
A distribution of (n_samples, m, n, o) shape is generated where (m, n, o) = size (input parameter). After that, we "flatten" it into a list of length n_samples where each item of that list is an array of shape (m, n, o).
Try This :
np.random.normal(0.0, 1.0, (100, 16, 16, 3))

Append a numpy array with different first dimensions

My program creates a numpy array within a for loop. For example it creates array with shape (100*30*10), then (160*30*10) and then may be (120*30*10) . I have to append the above to an empty numpy array such that , at the end of the loop, it will be a numpy array with shape (380*30*10) (i.e sum of 100+160+120) . The second and third dimension doesnt change in the numpy array.
How can I do the above in python. I tried the following.
np_model = np.append(np_model,np_temp1)
print("Appended model shape is",np_model.shape)
np_label = np.append(np_label,np_temp2)
print("Appended label shape is",np_label.shape)
The np_model is an empty array which I have defined as np_model = np.empty(1,30,10) and np_label as np_label = np.empty(1 ,str)
np_temp1 corresponds to array within each for loop like 100*30*10,120*30*10 etc and np_temp2 is a string with "item1","item2" etc
The np_label is a string numpy array with 1 label corresponding to np_temp1.shape[0]. But the result I get in np_model is flattened array with size 380*30*10 = 1140000
Any help is appreciated.
you can use numpy concatenate function, append the output numpy(s) to a list and then feed it to the concatenate function:
empty_list = []
x = np.zeros([10, 20, 4])
y = np.zeros([12, 20, 4])
empty_list.append(x)
empty_list.append(y)
z = np.concatenate(empty_list, axis=0)
print(x.shape, y.shape, z.shape)
(10, 20, 4) (12, 20, 4) (22, 20, 4)
As #Nullman suggested in comment(np.vstack)
You can create empty array like this >>> np_model = np.empty((0,30,10))
>>> np_model = np.empty((0,30,10))
>>> a = np.random.rand(100,30,10)
>>> b = np.random.rand(160,30,10)
>>> c = np.random.rand(120,30,10)
# It can done by one-line like`np_model = np.vstack((a,b,c))`
# but i guess you have loop dependency here
>>> np_model = np.vstack((np_model,a))
>>> np_model = np.vstack((np_model,b))
>>> np_model = np.vstack((np_model,c))
>>> np_model.shape
(380, 30, 10)
To specifically answer your question towards starting with an empty array, that'd be my solution, solely using np.concatenate:
import numpy as np
# Some arrays to append in a loop
arrays = (
np.random.rand(100, 30, 10),
np.random.rand(160, 30, 10),
np.random.rand(120, 30, 10)
)
# Initial empty array
array = np.zeros((0, 30, 10))
# Appending arrays in loop
for a in arrays:
array = np.concatenate((array, a), axis=0)
# Output shape
print(array.shape)
Output:
(380, 30, 10)
Hope that helps!
----------------------------------------
System information
----------------------------------------
Platform: Windows-10-10.0.16299-SP0
Python: 3.8.1
NumPy: 1.18.1
----------------------------------------

Image processing: vectorize numpy array elements substitution

The code works well but is very slow. How can I vectorize the color substitution to avoid usage of Python for loop?
processed_image = np.empty(initial_image.shape)
for i, j in np.ndindex(initial_image.shape[:2]):
l_, a, b = initial_image[i, j, :]
idx = mapping[a + 128, b + 128]
a, b = new_colors[tuple(idx)]
processed_image[i, j] = l_, a, b
I have an image initial_image in CIELAB space as numpy array of shape (some height, some width, 3). I need to produce a corrected image by changing a and b color components of image using mapping. mapping is a numpy array of shape (255, 255, 2). It gives me indices which can be used to get corrected a and b colors from new_colors. new_colors is of shape (table height, table width, 2).
Solutions that use scikit-image will also be helpful.
You can use advanced indexing:
# chain the two maps
chained = new_colors[(*np.moveaxis(mapping, 2, 0),)]
# split color channels
c1, *c23 = np.moveaxis(initial_image, 2, 0)
# add 128
c23 = *map(np.add, c23, (128, 128)),
# apply chained map
processed_image_2 = np.concatenate([c1[..., None], chained[c23]], axis=2)

How avoid changing numpy array's shape when appending?

i am trying to read 30 images and create a large numpy array from it by appending the numpy array for each image to that one single array so that i can use it later in a flow function for keras.
I have an empty list to which I am appending numpy arrays after doing face detection in a loop, after which I am creating a large numpy array from this list. The problem is that when,I create a numpy array from this list, it changes the shape of my array, which was originally (1,139,139,3), to (30,1,139,139,3). It basically adds the total number of images at the start as I am appending, and I want to get back to original shape. I do not want to use reshape as that might affect the data.
Here is the code:
img_width, img_height = 139, 139
confidence = 0.8
#graph = K.get_session().graph
data1 = []
def get_face(path):
with graph.as_default():
img = io.imread(path)
dets = detector(img, 1)
output = None
for i, d in enumerate(dets):
img = img[d.top():d.bottom(), d.left():d.right()]
img = resize(img, (img_width, img_height))
output = np.expand_dims(img, axis=0)
break
return output
for row in df.itertuples():
data1.append(get_face(row[1]))
data1 = np.array(data1)
print(data1)
As #filippo pointed out you probably want to omit np.expand_dims.
img_width, img_height = 139, 139
confidence = 0.8
#graph = K.get_session().graph
data1 = []
def get_face(path):
with graph.as_default():
img = io.imread(path)
dets = detector(img, 1)
output = None
for i, d in enumerate(dets):
img = img[d.top():d.bottom(), d.left():d.right()]
output = resize(img, (img_width, img_height))
break
return output
for row in df.itertuples():
data1.append(get_face(row[1]))
data1 = np.array(data1)
print(data1)
This piece of code will produce a list of 30 numpy arrays with shapes (139, 139, 3). Calling np.array constructor on that will give you array with shape (30, 139, 139, 3). You should also read documentation for np.stack and np.concatenate. Using the second function you can actually get what you want keeping np.expand_dims if for whatever reason you might need this.
np.array joins the elements of the list on a new front dimension:
In [141]: alist = []
In [142]: for i in range(2):
...: arr = np.zeros((3,4))
...: alist.append(arr)
...:
In [143]: np.array(alist).shape
Out[143]: (2, 3, 4)
expand_dims adds a new dimension:
In [144]: alist = []
In [145]: for i in range(2):
...: arr = np.zeros((3,4))
...: arr = np.expand_dims(arr,0)
...: alist.append(arr)
...:
In [146]: np.array(alist).shape
Out[146]: (2, 1, 3, 4)
concatenate joins on an existing dimension:
In [149]: np.concatenate(alist, axis=0).shape
Out[149]: (2, 3, 4)
An alternative to np.array is np.stack.

Alter a 3D ndarray at the positions represented by a 2d ndarray

This is my first nontrivial use of numpy, and I'm having some trouble in one spot.
So, I have colors, a (xsize + 2, ysize + 2, 3) ndarray, and newlife, a (xsize + 2, ysize + 2) ndarray of booleans. I want to add a random value between -5 and 5 to all three values in colors at all positions where newlife is true. In other words newlife maps 2D vectors to whether or not I want to add a random value to the color in colors at that position.
I've tried a million variations on this:
colors[np.nonzero(newlife)] += (np.random.random_sample((xsize + 2,ysize + 2, 3)) * 10 - 5)
but I keep getting stuff like
ValueError: operands could not be broadcast together with shapes (589,3) (130,42,3) (589,3)
How do I do this?
I think this does what you want:
# example data
colors = np.random.randint(0, 100, (5,4,3))
newlife = np.random.randint(0, 2, (5,4), bool)
# create values to add, then mask with newlife
to_add = np.random.randint(-5,6, (5,4,3))
to_add[~newlife] = 0
# modify in place
colors += to_add
This changes the colors in-place assuming uint8 dtype. Both assumptions are not essential:
import numpy as np
n_x, n_y = 2, 2
colors = np.random.randint(5, 251, (n_x+2, n_y+2, 3), dtype=np.uint8)
mask = np.random.randint(0, 2, (n_x+2, n_y+2), dtype=bool)
n_change = np.count_nonzero(mask)
print(colors)
print(mask)
colors[mask] += np.random.randint(-5, 6, (n_change, 3), dtype=np.int8).view(np.uint8)
print(colors)
The easiest way of understanding this is to look at the shape of colors[mask].

Categories

Resources