Assuming the input array is (n,m,3), then it can be expanded to (n,m,4) by simply concatenating a (n,m,1) array.
X = np.ones((n,m,3), dtype='byte')
F = np.zeros((n,m,1), dtype='byte')
X1 = np.concatenate([X,F], axis=2)
Strides for these are (3*m,3,1), (m,1,1) and (4*m,4,1).
The same data could put in
In [72]: dt0 = np.dtype([('R','u1'), ('G','u1'), ('B','u1')])
In [73]: X=np.ones((n,m),dtype=dt0)
In [74]: X.strides
Out[74]: (150, 3)
In [75]: X.shape
Out[75]: (30, 50)
With the target having dt = np.dtype([('R','u1'), ('G','u1'), ('B','u1'), ('A','u1')])
http://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html
Mapping RGB fields to RGBA
But to do concatenation with these dtypes, we'd do some sort of casting to the (n,m,3) shape. Looks like reassigning the data attribute will do the trick.
n, m = 2, 4
dt1 = np.dtype([('R','u1'), ('G','u1'), ('B','u1'), ('A','u1')])
dt0 = np.dtype([('R','u1'), ('G','u1'), ('B','u1')])
X = np.arange(n*m*3,dtype='u1').reshape(n,m,3)
print repr(X)
X0 = np.zeros((n,m), dtype=dt0)
X0.data = X.data
print repr(X0)
X0.strides # (12, 3)
X1 = np.zeros((n,m), dtype=dt1)
F = np.zeros((n,m,1), dtype='u1')
X01 = np.concatenate([X, F], axis=2)
X1.data = X01.data
print repr(X1)
X1.strides # (12, 4)
producing:
array([[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11)],
[(12, 13, 14), (15, 16, 17), (18, 19, 20), (21, 22, 23)]],
dtype=[('R', 'u1'), ('G', 'u1'), ('B', 'u1')])
array([[(0, 1, 2, 0), (3, 4, 5, 0), (6, 7, 8, 0), (9, 10, 11, 0)],
[(12, 13, 14, 0), (15, 16, 17, 0), (18, 19, 20, 0), (21, 22, 23, 0)]],
dtype=[('R', 'u1'), ('G', 'u1'), ('B', 'u1'), ('A', 'u1')])
Using overlapping dtypes
Here's a way of doing it with overlapping dtypes rather than concatenation:
dt0 = np.dtype([('R','u1'), ('G','u1'), ('B','u1')])
dt1 = np.dtype([('R','u1'), ('G','u1'), ('B','u1'), ('A','u1')])
dtb = np.dtype({'names':['rgb','rgba'],
'offsets':[0,0],
'formats':[dt0, dt1]})
X0 = np.zeros((n,m), dtype=dt0)
X0.data = X.data
X1 = np.zeros((n,m), dtype=dtb)
X1['rgb'][:] = X0
print repr(X1['rgba'])
Or without the individual named byte fields it's even simpler:
dt0 = np.dtype(('u1',(3,)))
dt1 = np.dtype(('u1',(4,)))
dtb = np.dtype({'names':['rgb','rgba'],
'offsets':[0,0],
'formats':[dt0, dt1]})
X = np.arange(n*m*3,dtype='u1').reshape(n,m,3)
X1 = np.zeros((n,m), dtype=dtb)
X1['rgb'][:] = X
X1['rgba'] is (n,m,4), with strides (m*4, 4, 1).
X1['rgb'] is (n,m,3), but with the same strides (m*4, 4, 1).
Using as_strided
That difference in shape, but similarity in strides, suggest's using as_strided. Create the empty target array, and use as_strided to select a subset of elements to receive values from X:
X1 = np.zeros((n,m,4),dtype='u1')
np.lib.stride_tricks.as_strided(X1, shape=X.shape, strides=X1.strides)[:] = X
print X1
(n,m,3)shape? And the output(n,m,4)? If so, how about concatenating anp.zeros((n,m,1))array?as_stridedsolution