Change all positive values in array to 1 (Python) - python

So I have several 3D arrays that I need to add together. Each array consists of entries with either 0 or 1. All arrays also have the same dimension. Now, when I add these arrays together some of the values overlap (which they do). However, I just need to know how the structure of the total combined array is, which means that I don't need the values 1, 2 or 3 when 2 or 3 arrays have overlapped. This also just need to be one, and of course, wherever there is a zero, the value zero just need to remain zero.
So basically what I have is:
array1 =
[[[1, 0, 0], [0, 0, 0], [0, 0, 0]],
[[0, 1, 0], [0, 0, 0], [0, 0, 0]],
[[0, 0, 1], [1, 1, 1], [0, 0, 0]]]
array2 =
[[[1, 0, 0], [0, 1, 0], [0, 0, 0]],
[[0, 0, 0], [1, 1, 0], [0, 0, 0]],
[[0, 0, 1], [0, 1, 0], [0, 0, 0]]]
So when adding them together I get:
array_total = array1 + array2 =
[[[2, 0, 0], [0, 1, 0], [0, 0, 0]],
[[0, 1, 0], [1, 1, 0], [0, 0, 0]],
[[0, 0, 2], [1, 2, 1], [0, 0, 0]]]
Where I actually want it to give me:
array_total = array1 + array2 =
[[[1, 0, 0], [0, 1, 0], [0, 0, 0]],
[[0, 1, 0], [1, 1, 0], [0, 0, 0]],
[[0, 0, 1], [1, 1, 1], [0, 0, 0]]]
So can anyone give me a hint to how this is done ?

(Assuming those are numpy arrays, or array1 + array2 would behave differently).
If you want to "change all positive values to 1", you can do this
array_total[array_total > 0] = 1
But what you actually want is an array that has a 1 where array1 or array2 has a 1, so just write it directly like that:
array_total = array1 | array2
Example:
>>> array1 = np.array([[[1, 0, 0], [0, 0, 0], [0, 0, 0]],
... [[0, 1, 0], [0, 0, 0], [0, 0, 0]],
... [[0, 0, 1], [1, 1, 1], [0, 0, 0]]])
>>> array2 = np.array([[[1, 0, 0], [0, 1, 0], [0, 0, 0]],
... [[0, 0, 0], [1, 1, 0], [0, 0, 0]],
... [[0, 0, 1], [0, 1, 0], [0, 0, 0]]])
>>> array1 | array2
array([[[1, 0, 0], [0, 1, 0], [0, 0, 0]],
[[0, 1, 0], [1, 1, 0], [0, 0, 0]],
[[0, 0, 1], [1, 1, 1], [0, 0, 0]]])

Related

Strange behavior of skimage.morphology.skeletonize3d

It is strange the if using skimage.morphology.skeletonize_3don structure as below. It will remove all elements. Such structure is a equilateral triangle in 3d space.
array = np.array([
[[0, 1, 0],
[0, 0, 1],
[0, 0, 0]],
[[0, 0, 0],
[0, 1, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]]).astype('uint8')
morphology.skeletonize_3d(array)
Output:
array([[[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]], dtype=uint8)
It results as an empty array. This is strange. Could anyone explain it? How to avoid it?

Convert a 2D numpy array into a hot-encoded 3D numpy array, with same values in the same plane

Suppose I have a Numpy array:
[
[0, 1, 0],
[0, 1, 4],
[2, 0, 0],
]
How can I turn this into a "hot encoded" 3D array? something like this:
[
# Group of 0's
[[1, 0, 1],
[1, 0, 0],
[0, 1, 1]],
# Group of 1's
[[0, 1, 0],
[0, 1, 0],
[0, 0, 0]],
# Group of 2's
[[0, 0, 0],
[0, 0, 0],
[1, 0, 0]],
# Group of 3's
# the group is still here, even though there are no threes
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
# Group of 4's
[[0, 0, 0],
[0, 0, 1],
[0, 0, 0]]
]
That is, how can I take each occurrence of a number in the array and "group" them into their own plane in a 3D matrix? As shown in the example, even the "gap" in numbers (i.e. the 3) should still appear. In my case, I know the range of the data beforehand (range (0, 6]), so that should make it easier.
BTW, I need this because I have a chessboard represented by numbers, but need it in this form to pass into a 2d convolutional neural network (different "channels" for different pieces).
I've seen Convert a 2d matrix to a 3d one hot matrix numpy, but that has a one-hot encoding for every value, which isn't what I'm looking for.
Create the desired array (arr.max()+1 here) and then reshape it to compare to the original array:
Setup:
arr = np.array([
[0, 1, 0],
[0, 1, 4],
[2, 0, 0],
])
u = np.arange(arr.max()+1)
(u[:,np.newaxis,np.newaxis]==arr).astype(int)
array([[[1, 0, 1],
[1, 0, 0],
[0, 1, 1]],
[[0, 1, 0],
[0, 1, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[1, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 1],
[0, 0, 0]]])

Numpy-like indexing and assignment with Tensorflow

I made a simple example of numpy array indexing and assignment where the goal is to make a small white square on a black screen.
How would I replicate the following code using Tensorflow?
black_img = np.zeros([5, 5, 3])
white_rect = np.ones([3, 3])
size = np.arange(3)
black_img[size, size] = white_rect
You can create constants or variables in TensorFlow.
black_img = np.zeros([5, 5, 3], dtype = np.int32)
black_img_tf = tf.constant(np.zeros([5, 5, 3], dtype = np.int32))
Output:
<tf.Tensor: shape=(5, 5, 3), dtype=int32, numpy=
array([[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]])>
However, TensorFlow does not support item assignment like NumPy.
However, you can create a new constant or variable using results obtained from NumPy operations.
Code:
black_img[size, size] = white_rect
tf.constant(black_img)
Output:
<tf.Tensor: shape=(5, 5, 3), dtype=int32, numpy=
array([[[1, 1, 1],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[1, 1, 1],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[1, 1, 1],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]])>
Note that individual item assignment is not allowed but you can do operations like addition, subtraction on tensors.
c = tf.constant(np.ones([3, 3], dtype = np.int32)) + tf.constant(np.ones([3, 3], dtype = np.int32))
c
Output:
<tf.Tensor: shape=(3, 3), dtype=int32, numpy=
array([[2, 2, 2],
[2, 2, 2],
[2, 2, 2]])>

Numpy: filling the non-maximum elements of ndarray with zeros

I have a ndarray, and I want to set all the non-maximum elements in the last dimension to be zero.
a = np.array([[[1,8,3,4],[6,7,10,6],[11,12,15,4]],
[[4,2,3,4],[4,7,9,8],[41,14,15,3]],
[[4,22,3,4],[16,7,9,8],[41,12,15,43]]
])
print(a.shape)
(3,3,4)
I can get the indexes of maximum elements by np.argmax():
b = np.argmax(a, axis=2)
b
array([[1, 2, 2],
[0, 2, 0],
[1, 0, 3]])
Obviously, b has 1 dimension less than a. Now, I want to get a new 3-d array that has all zeros except for where the maximum values are.
I want to get this array:
np.array([[[0,1,0,0],[0,0,1,0],[0,0,1,0]],
[[1,0,0,1],[0,0,1,0],[1,0,0,0]],
[[0,1,0,0],[1,0,0,0],[0,0,0,1]]
])
One way to achieve this, I tried creating these temporary arrays
b = np.repeat(b[:,:,np.newaxis], 4, axis=2)
t = np.repeat(np.arange(4).reshape(4,1), 9, axis=1).T.reshape(b.shape)
z = np.zeros(shape=a.shape, dtype=int)
z[t == b] = 1
z
array([[[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 1, 0]],
[[1, 0, 0, 0],
[0, 0, 1, 0],
[1, 0, 0, 0]],
[[0, 1, 0, 0],
[1, 0, 0, 0],
[0, 0, 0, 1]]])
Any idea how to get this in a more efficient way?
Here's one way that uses broadcasting:
In [108]: (a == a.max(axis=2, keepdims=True)).astype(int)
Out[108]:
array([[[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 1, 0]],
[[1, 0, 0, 1],
[0, 0, 1, 0],
[1, 0, 0, 0]],
[[0, 1, 0, 0],
[1, 0, 0, 0],
[0, 0, 0, 1]]])

label 3d numpy array with scipy.ndimage.label

I've got a large 3d numpy array which consists of ones and zeros. I would like to use the scipy.ndimage.label tool to label the features in each sub-array (2d).
A subset of the 3d-array looks like:
import numpy as np
from scipy.ndimage import label
subset = np.array([[[1, 0, 0],
[1, 0, 1],
[0, 0, 0]],
[[0, 0, 0],
[1, 0, 1],
[0, 0, 1]],
[[0, 0, 0],
[1, 0, 0],
[0, 1, 1]],
[[0, 0, 0],
[1, 0, 0],
[1, 1, 1]]], dtype=uint8)
When I use the label tool on a small part of this subset is works correct:
>>>label(subset[0:3])
(array([[[1, 0, 0],
[1, 0, 2],
[0, 0, 0]],
[[0, 0, 0],
[1, 0, 2],
[0, 0, 2]],
[[0, 0, 0],
[1, 0, 0],
[0, 2, 2]]]), 2)
However, when I use the entire subset the label tool is not working properly:
>>>label(subset)
(array([[[1, 0, 0],
[1, 0, 1],
[0, 0, 0]],
[[0, 0, 0],
[1, 0, 1],
[0, 0, 1]],
[[0, 0, 0],
[1, 0, 0],
[0, 1, 1]],
[[0, 0, 0],
[1, 0, 0],
[1, 1, 1]]]), 1)
Any ideas how this problem can be tackled?
ps.
The complete array which I am trying to label consists of 350219 2d arrays.
I answered this question with the help of dan-man.
I had to define a new 3D structure for the label tool:
import numpy as np
from scipy.dimage import label
str_3D = np.array([[[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 1, 0],
[1, 1, 1],
[0, 1, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]], dtype='uint8')
Now the label returns the following for my subset:
>>> label(subset, structure=str_3D)
# outputs:
(array([[[1, 0, 0],
[1, 0, 2],
[0, 0, 0]],
[[0, 0, 0],
[3, 0, 4],
[0, 0, 4]],
[[0, 0, 0],
[5, 0, 0],
[0, 6, 6]],
[[0, 0, 0],
[7, 0, 0],
[7, 7, 7]]]), 7)

Categories

Resources