Reputation: 4440
I am new to Numpy and OpenCV. I find it odd that Numpy arrays can be indexed with ranges only for the first dimension:
>>> import numpy
>>>
>>> a = numpy.zeros((3, 3), dtype=numpy.int8)
>>>
>>> i_range = range(3)
>>> j_range = range(3)
>>>
>>> print(i_range)
range(0, 3)
>>> print(j_range)
range(0, 3)
>>> print(a[i_range, j_range])
[0 0 0]
>>> print(a[0:3, 0:3])
[[0 0 0]
[0 0 0]
[0 0 0]]
>>> a[i_range, j_range] = numpy.ones((3,3), dtype=numpy.int8)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: shape mismatch: value array of shape (3,3) could not be broadcast to indexing result of shape (3,)
>>> a[0:3, 0:3] = numpy.ones((3,3), dtype=numpy.int8)
>>> a
array([[1, 1, 1],
[1, 1, 1],
[1, 1, 1]], dtype=int8)
Indexing with ranges returns a vector of length 3, indexing with full numbers returns a 3x3 array. The former throws an error when assigning values to indexed arrays, the latter works fine.
Why does that happen?
Upvotes: 0
Views: 150
Reputation: 231738
That fact that you are using range
instead of a list, has nothing to do with your error.
Make an array with distinctive values:
In [30]: a = np.arange(9).reshape(3,3)
In [31]: a
Out[31]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
Indexing with two ranges produces a 1d array, in this case the diagonal.
In [32]: a[range(3),range(3)]
Out[32]: array([0, 4, 8])
a[[0,1,2], [0,1,2]]
would do the same thing. The (3,) block in your error refers to this 1d array.
To get a block equivalent to the [0:3, 0:3]
slicing, you have to use arrays that broadcast against each other. A handy utility is ix_
:
In [33]: np.ix_(range(3), range(3))
Out[33]:
(array([[0],
[1],
[2]]), array([[0, 1, 2]]))
Note that one array is (3,1), the other (1,3); broadcasted together they reference a (3,3) block of values:
In [34]: a[np.ix_(range(3), range(3))]
Out[34]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
Now we can assign a (3,3) array of values to it:
In [35]: a[np.ix_(range(3), range(3))] = np.ones((3,3))
In [36]: a
Out[36]:
array([[1, 1, 1],
[1, 1, 1],
[1, 1, 1]])
Upvotes: 1
Reputation: 116
The difference is that in Python 3.x, range() produces an iterator and not a list. Until Python 2.x, this functionality was used by xrange(). However, now, simply calling range() produces an iterator.
Upvotes: 0