Reputation:
I want to use np.isclose() to compare pixel arrays of an image. Below is what I'm trying to do:
print(image_array.shape) # (320, 240, 4)
for i in range(0, len(image_array)):
for j in range(0, len(image_array[i])):
if np.isclose(image_array[i][j], [1, 0, 0, 1]):
image_array[i][j] = [0, 1, 0, 1]
But I am getting the following error ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
.
I cannot use np.all() because I want to replace all pixels that are even close enough.
Upvotes: 1
Views: 1234
Reputation: 231540
image_array[i,j]
is a shape (4,) array (you can check that). isclose
with that and [1,0,0,1]
is a like size boolean array. It can't be used in an if
. But you can apply all
to that, or use allclose
to test if a 'pixel' matches.
But without the double loop you can test as follows:
In [381]: arr = np.random.randint(0,2,(3,6,4))
In [382]: arr.shape
Out[382]: (3, 6, 4)
In [383]: np.isclose(arr,np.array([1,0,0,1]))
Out[383]:
array([[[ True, True, False, False],
[False, False, True, True],
[ True, True, True, False],
[False, False, True, False],
[ True, False, False, True],
[ True, False, False, False]],
[[False, True, False, False],
[ True, True, True, False],
[ True, False, False, True],
[False, False, True, True],
[False, True, True, False],
[False, False, True, True]],
[[False, False, False, True],
[ True, True, True, True],
[ True, True, False, False],
[ True, False, True, True],
[False, False, False, False],
[False, False, False, True]]])
(Since I used randint
arr
is int
dtype, and ==
would be just as good as isclose
. But the following is the same.
Applying all
on the last dimension:
In [384]: np.isclose(arr,np.array([1,0,0,1])).all(axis=-1)
Out[384]:
array([[False, False, False, False, False, False],
[False, False, False, False, False, False],
[False, True, False, False, False, False]])
here one 'pixel' matches, which we can identify with:
In [385]: I,J = np.nonzero(_)
In [386]: I,J
Out[386]: (array([2]), array([1]))
In [387]: arr[2,1]
Out[387]: array([1, 0, 0, 1])
Or indexing the 2 arrays:
In [389]: arr[I,J]
Out[389]: array([[1, 0, 0, 1]])
This is a (n,4) array, where n
is the number of matches (which could be 0). And we can modify arr
with that:
In [390]: arr[I,J]=[1,0,1,0]
now there's not match:
In [391]: np.isclose(arr,np.array([1,0,0,1])).all(axis=-1)
Out[391]:
array([[False, False, False, False, False, False],
[False, False, False, False, False, False],
[False, False, False, False, False, False]])
but there are now 3 matches to the new value:
In [392]: np.isclose(arr,np.array([1,0,1,0])).all(axis=-1)
Out[392]:
array([[ True, False, False, False, False, False],
[False, False, False, False, False, False],
[False, True, True, False, False, False]])
In [393]: arr[_] # index with the boolean mask
Out[393]:
array([[1, 0, 1, 0],
[1, 0, 1, 0],
[1, 0, 1, 0]])
Upvotes: 0
Reputation: 501
Rather than using np.isclose
, use np.allclose
. This will return a single boolean value for that comparison.
Upvotes: 2
Reputation: 1166
From the documentation - isclose
"Returns a boolean array where two arrays are element-wise equal within a tolerance."
Thus, there is an array of boolean values returned which represents the is-close-ness of each value of the 4-element array. It's up to you to convert that array to a single boolean value.
You might, for instance, only care if any of the 4 match, in which case you can use any()
; alternatively, if you care if all match, you can use all()
.
Upvotes: 0