How to remove matrices in a numpy array of matrices? - python

I have a numpy array arr_seg_labs which has the following shape: (1735, 128, 128).
It contains pixel masks between 1 and 10 and also contains zeros and 255 (background).
I want to remove those (128, 128) matrices which not contain the given category identifier (9) and to keep those which contain at least one 9.
I made a mask (horse_mask) for this, but I don't know how can I continue this thread to filter this numpy array
CAT_IDX_HORSE = 9
horse_mask = arr_seg_labs == CAT_IDX_HORSE

IIUC you can use masks and indexing as:
CAT_IDX_HORSE = 9
mask = (a == CAT_IDX_HORSE ).sum((1, 2))
result = a[mask != 0]

Related

Split matrices into smaller blocks and do something based on its values

I have a numpy array ys_big_seg which has the following shape: (146, 128, 128). It contains pixel masks which values can be 0 or 1. 1 if the pixel is in a given category otherwise 0. I have to scale it to binary mask. So I want to iterate through the (128, 128) matrices and split it to (8, 8) matrices and then based on the smaller matrices values (if every element is 0 then 0, if every element is 1 then 1, if there are mixed values then randomly 0 or 1) substitute these smaller matrices with given values to reduce the (128, 128) matrices to (16, 16).
How can I solve this problem?
I hope it makes sense, sorry for my English.
I think this does what you're looking for:
>>> x.shape
(146, 128, 128)
>>> mask = x.reshape(-1, 16, 16, 8, 8).sum(axis=(3, 4)) >= 32
>>> mask.shape
(146, 16, 16)
Any 8x8 block with a mixture of 0s and 1s will result in a 1 if the total sum is >= 32 (i.e., half or more of the values values are 1), so it's not quite randomly chosen.
Obviously, a sum of 0 (all elements in an 8x8 block are 0) will "fail" that criteria and be 0, and a sum of 64 (all elements in an 8x8 block are 1) will "pass" and end up as a 1. If your matrices are a lot more sparse, you could lower the threshold from 32.
Since you're using this array as a mask, you can leave the 1s and 0s as their boolean counterparts. But if you plan to use the mask as a binary array, then you can easily add .astype(int).

Masking arrays using numpy

I have an array and I want to mask it such that I Keep its shape as it is i.e, not to delete the masked elements.
For example in this code
input = torch.randn(2, 5)
mask = input > 0
input = input[mask]
input = input *1000000000000
print(input)
printing the input is the result of the above mathematical operation on the unmasked elements and returns a 1D array without the masked elements.
you're overwriting your original array when you do input = input[mask]. If you omit that step, you can modify the masked values in place, but keep the non-masked values as is
i = np.random.randn(2, 5)
print(i)
[[ 0.48857855 0.97799014 2.29587523 -2.37257331 1.28193921]
[ 0.62932172 1.37433223 -1.2427145 0.31424802 1.34534568]]
mask = i> 0
i[mask] *= 1000000000000
print(i)
[[ 4.88578545e+11 9.77990142e+11 2.29587523e+12 -2.37257331e+00 1.28193921e+12]
[ 6.29321720e+11 1.37433223e+12 -1.24271450e+00 3.14248021e+11 1.34534568e+12]]

Select elements of numpy array via mask and preserving original dimensions

Hello I have following data
ids = np.concatenate([1.0 * np.ones(shape=(4, 9,)),
2.0 * np.ones(shape=(4, 3,))], axis=1)
logits = np.random.normal(size=(4, 9 + 3, 256))
Now I want to get numpy array only of ids that have 1.0 and I want to get array of size (4,9, 256)
I tried logits[ids == 1.0, :] but I get (36, 256)
How I can make slicing without connecting first two dimensions ?
Current dimensions are only example ones and I am looking for generic solution.
Your question appears to assume that each row has the same number of nonzero entries; in that case you can solve your problem generally like this:
mask = (ids == 1)
num_per_row = mask.sum(1)
# same number of entries per row is required
assert np.all(num_per_row == num_per_row[0])
result = logits[mask].reshape(logits.shape[0], num_per_row[0], logits.shape[2])
print(result.shape)
# (4, 9, 256)

Counting unique rgb

I have found a working code for this, but don't understand everything about these lines:
counter = np.unique(img.reshape(-1, img.shape[2]), axis=0)
print(counter.shape[0])
Especially these values:
-1, img.shape[2], axis=0
What does that -1 do, why is the shape 2, and why is axis 0?
And after that, why do we print shape[0]?
If you don't understand a complex sentence, always break them up and print shapes.
print(img.shape)
img2 = img.reshape(-1, img.shape[2]) # reshape the original image into -1, 3; -1 is placeholder, so lets say you have a
# numpy array with shape (6,2), if you reshape it to (-1, 3), we know the second dim = 3
# first dim = (6*2)/3 = 4, so -1 is replaced with 4
print(img2.shape)
counter = np.unique(img2, axis=0) # find unique elemenst
'''
numpy.unique(ar, return_index=False, return_inverse=False, return_counts=False, axis=None)[source]
Find the unique elements of an array.
Returns the sorted unique elements of an array. There are three optional outputs in addition to the unique elements:
the indices of the input array that give the unique values
the indices of the unique array that reconstruct the input array
the number of times each unique value comes up in the input array
'''
print(counter)
print(counter.shape) # as, we have separate axis, so the channels are shown in dim 2
print(counter.shape[0])
But, this one is probably not correct as it doesn't consider unique RGB across channel.
So, the following is a better one, you flatten the array to get a list then using set find the unique elements and finally print the len of the set.
A handy shortcut is ->
print(len(set(img.flatten())))
Try this:
a = np.array([
[[1,2,3],[1,2,3],[1,2,3],[1,2,3]],
[[1,2,3],[1,2,3],[1,2,3],[1,2,3]]
])
a # to print the contents
a.shape # returns 2, 4, 3
Now, if you do reshape, it will change the shape, meaning it will re-arrange the items in the array.
# try:
a.reshape(2, 4, 3)
a.reshape(4, 2, 3)
# or even
a.reshape(12, 2, 1)
a.reshape(1, 1, 4, 2, 3)
a.reshape(1, 1, 4, 2, 1, 1, 3)
# or:
a.reshape(24, 1)
a.reshape(1, 24)
If you replace one of the numbers with -1, it will get calculated automatically. So:
a.reshape(-1, 3)
# is the same as
a.reshape(8, 3)
and that'll give you the a "vector" of RGB values in a way.
So now you have got the reshaped array and you just need to count unique values.
np.unique(a.reshape(8, 3), axis=0)
will return an array of unique values over axis 0 and you will just count them.
It is calculating the number of unique RGB pixel values in the image. In other word it is calculation the number of different colors in the images
img.reshape(-1, img.shape[2]) : A three channel image flattened per channel. A 3 channel image is of shape width x height x 3 where each channels (3 here) corresponds to RGB or BGR depending on how you read the image. We are reshaping it into 2 dimensions, RGB values per channel. So second dimension will be number of channels. so if you know the width and height of image, it is equal to img.reshape(w*h, img.shape[2]) which is same as img.rehape(img.shape[0]*img.shape[1], img.shape[2]). Intutively think of it like you are taking a 3 channel image and laying out the colors of pixels one after the other. In numpy you can always leave out one dimension as -1 which is automatically calculated based on the shape of the object and the other dimensions.
Now that we have layed out pixes one after the other we can calculate the number of unique colors, but since color is represented by 3 (RGB) values we want to calculated unique RGB values which is done by using np.unique over the second dimension which is channel. This returns all the unique RGB values, which will be of size n x 3 where n are the unique pixel values. Finally since we want to find the count, shape will return (n,3) we select shape[0] which will return n.
Code
# image of size 200 X 200 X 3 => 200 pixels width 200 pixels height => total 200*200 pixels
img = np.random.randint(0,256, (200,200,3))
print (img.shape)
# Flatten the image to 200*200 pixels
img = img.reshape(-1, img.shape[2])
print (img.shape)
# Count unique colors
counter = np.unique(img, axis=0)
# n unique colors (3 values per pixel)
print (counter.shape)
Output
(200, 200, 3)
(40000, 3)
(39942, 3)

Is this a right Numpy reshape?

I've just started with Python and Numpy.
I have found this piece of code:
def preprocessing(FLAIR_array, T1_array):
brain_mask = np.ndarray(np.shape(FLAIR_array), dtype=np.float32)
brain_mask[FLAIR_array >=thresh] = 1
brain_mask[FLAIR_array < thresh] = 0
for iii in range(np.shape(FLAIR_array)[0]):
brain_mask[iii,:,:] = scipy.ndimage.morphology.binary_fill_holes(brain_mask[iii,:,:]) #fill the holes inside brain
FLAIR_array -=np.mean(FLAIR_array[brain_mask == 1]) #Gaussion Normalization
FLAIR_array /=np.std(FLAIR_array[brain_mask == 1])
rows_o = np.shape(FLAIR_array)[1]
cols_o = np.shape(FLAIR_array)[2]
FLAIR_array = FLAIR_array[:, int((rows_o-rows_standard)/2):int((rows_o-rows_standard)/2)+rows_standard, int((cols_o-cols_standard)/2):int((cols_o-cols_standard)/2)+cols_standard]
What are they doing in the last line? In this one:
FLAIR_array[:, int((rows_o-rows_standard)/2):int((rows_o-rows_standard)/2)+rows_standard, int((cols_o-cols_standard)/2):int((cols_o-cols_standard)/2)+cols_standard]
FLAIR_array has this shape: [48,240,240].
48 is the number of images.
240, 240 is its height and witdh.
Or maybe, they are slicing it.
Yes, they're only performing Numpy slicing (and not reshaping) on FLAIR_array whose resultant dimensions will be:
All elements in the 0th dimension are retained from the original array (as indicated by :)
Elements int((rows_o-rows_standard)/2) to int((rows_o-rows_standard)/2)+rows_standard - 1 are used from 1st dimension from the original array
Elements int((cols_o-cols_standard)/2) to int((cols_o-cols_standard)/2)+cols_standard - 1 are used from 2nd dimension from the original array
Hard to tell, as rows standard is not defined inside the function.
But if you rewrite it as (dropping some of the int(..) to increase readability)
rows_center = int(rows_o/2)
cols_center = int(cols_o/2)
delta_rows = int(rows_standard)
delta_cols = int(cols_standard)
FLAIR_array = FLAIR_array[:, rows_center - rows_delta/2:rows_center + rows_delta/2, cols_center - cols_delta/2:cols_center + cols_delta/2]
It seems that they are extracting for each image a small crop centered at rows_center and cols_center with the number of rows and columns equal to delta_rows, delta_cols

Categories