Reputation: 15406
I find the astype() method of numpy arrays not very efficient. I have an array containing 3 million of Uint8 point. Multiplying it by a 3x3 matrix takes 2 second, but converting the result from uint16 to uint8 takes another second.
More precisely :
print time.clock()
imgarray = np.dot(imgarray, M)/255
print time.clock()
imgarray = imgarray.clip(0, 255)
print time.clock()
imgarray = imgarray.astype('B')
print time.clock()
dot product and scaling takes 2 sec
clipping takes 200 msec
type conversion takes 1 sec
Given the time taken by the other operations, I would expect astype
to be faster.
Is there a faster way to do type conversion, or am I wrong when guesstimating that type conversion should not be that hard ?
Edit : the goal is to save the final 8 bit array to a file
Upvotes: 15
Views: 39440
Reputation: 879143
When you use imgarray = imgarray.astype('B')
, you get a copy of the array, cast to the specified type. This requires extra memory allocation, even though you immediately flip imgarray to point to the newly allocated array.
If you use imgarray.view('uint8')
, then you get a view of the array. This uses the same data except that it is interpreted as uint8
instead of imgarray.dtype
.
(np.dot
returns a uint32
array, so after the np.dot
, imgarray
is of type uint32
.)
The problem with using view
, however, is that a 32-bit integer becomes viewed as 4 8-bit integers, and we only care about the value in the last 8-bits. So we need to skip to every 4th 8-bit integer. We can do that with slicing:
imgarray.view('uint8')[:,::4]
IPython's %timeit command shows there is a significant speed up doing things this way:
In [37]: %timeit imgarray2 = imgarray.astype('B')
10000 loops, best of 3: 107 us per loop
In [39]: %timeit imgarray3 = imgarray.view('B')[:,::4]
100000 loops, best of 3: 3.64 us per loop
Upvotes: 27