Related
I have an image.
I want to obtain a 3x3 window (neighbouring pixels) for every pixel in the image.
I have this Python code:
for x in range(2,r-1,1):
for y in range(2,c-1,1):
mask5=numpy.array([cv.Get2D(copy_img,x-1,y-1),cv.Get2D(copy_img,x-1,y),cv.Get2D(copy_img,x-1,y+1),cv.Get2D(copy_img,x,y-1),cv.Get2D(copy_img,x,y),cv.Get2D(copy_img,x,y+1),cv.Get2D(copy_img,x+1,y-1),cv.Get2D(copy_img,x+1,y),cv.Get2D(copy_img,x+1,y+1)])
cent=[cv.Get2D(copy_img,x,y)]
mask5 is the 3x3 window. cent is the center pixel.
Is there a more efficient way to do this - i.e. using maps, iterators - anything but the two nested loops I've used?
This can be done faster, by reshaping and swapping axes, and then repeating over all kernel elements, like this:
im = np.arange(81).reshape(9,9)
print np.swapaxes(im.reshape(3,3,3,-1),1,2)
This gives you an array of 3*3 tiles which tessalates across the surface:
[[[[ 0 1 2] [[ 3 4 5] [[ 6 7 8]
[ 9 10 11] [12 13 14] [15 16 17]
[18 19 20]] [21 22 23]] [24 25 26]]]
[[[27 28 29] [[30 31 32] [[33 34 35]
[36 37 38] [39 40 41] [42 43 44]
[45 46 47]] [48 49 50]] [51 52 53]]]
[[[54 55 56] [[57 58 59] [[60 61 62]
[63 64 65] [66 67 68] [69 70 71]
[72 73 74]] [75 76 77]] [78 79 80]]]]
To get the overlapping tiles we need to repeat this 8 further times, but 'wrapping' the array, by using a combination of vstack and column_stack. Note that the right and bottom tile arrays wrap around (which may or may not be what you want, depending on how you are treating edge conditions):
im = np.vstack((im[1:],im[0]))
im = np.column_stack((im[:,1:],im[:,0]))
print np.swapaxes(im.reshape(3,3,3,-1),1,2)
#Output:
[[[[10 11 12] [[13 14 15] [[16 17 9]
[19 20 21] [22 23 24] [25 26 18]
[28 29 30]] [31 32 33]] [34 35 27]]]
[[[37 38 39] [[40 41 42] [[43 44 36]
[46 47 48] [49 50 51] [52 53 45]
[55 56 57]] [58 59 60]] [61 62 54]]]
[[[64 65 66] [[67 68 69] [[70 71 63]
[73 74 75] [76 77 78] [79 80 72]
[ 1 2 3]] [ 4 5 6]] [ 7 8 0]]]]
Doing it this way you wind up with 9 sets of arrays, so you then need to zip them back together. This, and all the reshaping generalises to this (for arrays where the dimensions are divisible by 3):
def new(im):
rows,cols = im.shape
final = np.zeros((rows, cols, 3, 3))
for x in (0,1,2):
for y in (0,1,2):
im1 = np.vstack((im[x:],im[:x]))
im1 = np.column_stack((im1[:,y:],im1[:,:y]))
final[x::3,y::3] = np.swapaxes(im1.reshape(rows/3,3,cols/3,-1),1,2)
return final
Comparing this new function to looping through all the slices (below), using timeit, its about 4 times faster, for a 300*300 array.
def old(im):
rows,cols = im.shape
s = []
for x in xrange(1,rows):
for y in xrange(1,cols):
s.append(im[x-1:x+2,y-1:y+2])
return s
I think the following does what you are after. The loop is only over the 9 elements. I'm sure there is a way of vectorizing it, but it's probably not worth the effort.
import numpy
im = numpy.random.randint(0,50,(5,7))
# idx_2d contains the indices of each position in the array
idx_2d = numpy.mgrid[0:im.shape[0],0:im.shape[1]]
# We break that into 2 sub arrays
x_idx = idx_2d[1]
y_idx = idx_2d[0]
# The mask is used to ignore the edge values (or indeed any values).
mask = numpy.ones(im.shape, dtype='bool')
mask[0, :] = False
mask[:, 0] = False
mask[im.shape[0] - 1, :] = False
mask[:, im.shape[1] - 1] = False
# We create and fill an array that contains the lookup for every
# possible 3x3 array.
idx_array = numpy.zeros((im[mask].size, 3, 3), dtype='int64')
# Compute the flattened indices for each position in the 3x3 grid
for n in range(0, 3):
for m in range(0, 3):
# Compute the flattened indices for each position in the
# 3x3 grid
idx = (x_idx + (n-1)) + (y_idx + (m-1)) * im.shape[1]
# mask it, and write it to the big array
idx_array[:, m, n] = idx[mask]
# sub_images contains every valid 3x3 sub image
sub_images = im.ravel()[idx_array]
# Finally, we can flatten and sort each sub array quickly
sorted_sub_images = numpy.sort(sub_images.reshape((idx[mask].size, 9)))
Try the following code as matlab function im2col(...)
import numpy as np
def im2col(Im, block, style='sliding'):
"""block = (patchsize, patchsize)
first do sliding
"""
bx, by = block
Imx, Imy = Im.shape
Imcol = []
for j in range(0, Imy):
for i in range(0, Imx):
if (i+bx <= Imx) and (j+by <= Imy):
Imcol.append(Im[i:i+bx, j:j+by].T.reshape(bx*by))
else:
break
return np.asarray(Imcol).T
if __name__ == '__main__':
Im = np.reshape(range(6*6), (6,6))
patchsize = 3
print Im
out = im2col(Im, (patchsize, patchsize))
print out
print out.shape
print len(out)
I've taken it upon myself to learn how NumPy works for my own curiosity.
It seems that the simplest function is the hardest to translate to code (I understand by code). It's easy to hard code each axis for each case but I want to find a dynamic algorithm that can sum in any axis with n-dimensions.
The documentation on the official website is not helpful (It only shows the result not the process) and it's hard to navigate through Python/C code.
Note: I did figure out that when an array is summed, the axis specified is "removed", i.e. Sum of an array with a shape of (4, 3, 2) with axis 1 yields an answer of an array with a shape of (4, 2)
Setup
consider the numpy array a
a = np.arange(30).reshape(2, 3, 5)
print(a)
[[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
[[15 16 17 18 19]
[20 21 22 23 24]
[25 26 27 28 29]]]
Where are the dimensions?
The dimensions and positions are highlighted by the following
p p p p p
o o o o o
s s s s s
dim 2 0 1 2 3 4
| | | | |
dim 0 ↓ ↓ ↓ ↓ ↓
----> [[[ 0 1 2 3 4] <---- dim 1, pos 0
pos 0 [ 5 6 7 8 9] <---- dim 1, pos 1
[10 11 12 13 14]] <---- dim 1, pos 2
dim 0
----> [[15 16 17 18 19] <---- dim 1, pos 0
pos 1 [20 21 22 23 24] <---- dim 1, pos 1
[25 26 27 28 29]]] <---- dim 1, pos 2
↑ ↑ ↑ ↑ ↑
| | | | |
dim 2 p p p p p
o o o o o
s s s s s
0 1 2 3 4
Dimension examples:
This becomes more clear with a few examples
a[0, :, :] # dim 0, pos 0
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
a[:, 1, :] # dim 1, pos 1
[[ 5 6 7 8 9]
[20 21 22 23 24]]
a[:, :, 3] # dim 2, pos 3
[[ 3 8 13]
[18 23 28]]
sum
explanation of sum and axis
a.sum(0) is the sum of all slices along dim 0
a.sum(0)
[[15 17 19 21 23]
[25 27 29 31 33]
[35 37 39 41 43]]
same as
a[0, :, :] + \
a[1, :, :]
[[15 17 19 21 23]
[25 27 29 31 33]
[35 37 39 41 43]]
a.sum(1) is the sum of all slices along dim 1
a.sum(1)
[[15 18 21 24 27]
[60 63 66 69 72]]
same as
a[:, 0, :] + \
a[:, 1, :] + \
a[:, 2, :]
[[15 18 21 24 27]
[60 63 66 69 72]]
a.sum(2) is the sum of all slices along dim 2
a.sum(2)
[[ 10 35 60]
[ 85 110 135]]
same as
a[:, :, 0] + \
a[:, :, 1] + \
a[:, :, 2] + \
a[:, :, 3] + \
a[:, :, 4]
[[ 10 35 60]
[ 85 110 135]]
default axis is -1
this means all axes. or sum all numbers.
a.sum()
435
I use a nested loop operation to explain it.
import numpy as np
n = np.array(
[[[1, 2, 3],
[4, 5, 6],
[7, 8, 9]],
[[2, 4, 6],
[8, 10, 12],
[14, 16, 18]],
[[1, 3, 5],
[7, 9, 11],
[13, 15, 17]]])
print(n)
print("============ sum axis=None=============")
sum = 0
for i in range(3):
for j in range(3):
for k in range(3):
sum += n[k][i][j]
print(sum) # 216
print('------------------')
print(np.sum(n)) # 216
print("============ sum axis=0 =============")
for i in range(3):
for j in range(3):
sum = 0
for axis in range(3):
sum += n[axis][i][j]
print(sum,end=' ')
print()
print('------------------')
print("sum[0][0] = %d" % (n[0][0][0] + n[1][0][0] + n[2][0][0]))
print("sum[1][1] = %d" % (n[0][1][1] + n[1][1][1] + n[2][1][1]))
print("sum[2][2] = %d" % (n[0][2][2] + n[1][2][2] + n[2][2][2]))
print('------------------')
print(np.sum(n, axis=0))
print("============ sum axis=1 =============")
for i in range(3):
for j in range(3):
sum = 0
for axis in range(3):
sum += n[i][axis][j]
print(sum,end=' ')
print()
print('------------------')
print("sum[0][0] = %d" % (n[0][0][0] + n[0][1][0] + n[0][2][0]))
print("sum[1][1] = %d" % (n[1][0][1] + n[1][1][1] + n[1][2][1]))
print("sum[2][2] = %d" % (n[2][0][2] + n[2][1][2] + n[2][2][2]))
print('------------------')
print(np.sum(n, axis=1))
print("============ sum axis=2 =============")
for i in range(3):
for j in range(3):
sum = 0
for axis in range(3):
sum += n[i][j][axis]
print(sum,end=' ')
print()
print('------------------')
print("sum[0][0] = %d" % (n[0][0][0] + n[0][0][1] + n[0][0][2]))
print("sum[1][1] = %d" % (n[1][1][0] + n[1][1][1] + n[1][1][2]))
print("sum[2][2] = %d" % (n[2][2][0] + n[2][2][1] + n[2][2][2]))
print('------------------')
print(np.sum(n, axis=2))
print("============ sum axis=(0,1)) =============")
for i in range(3):
sum = 0
for axis1 in range(3):
for axis2 in range(3):
sum += n[axis1][axis2][i]
print(sum,end=' ')
print()
print('------------------')
print("sum[1] = %d" % (n[0][0][1] + n[0][1][1] + n[0][2][1] +
n[1][0][1] + n[1][1][1] + n[1][2][1] +
n[2][0][1] + n[2][1][1] + n[2][2][1] ))
print('------------------')
print(np.sum(n, axis=(0,1)))
result:
[[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]]
[[ 2 4 6]
[ 8 10 12]
[14 16 18]]
[[ 1 3 5]
[ 7 9 11]
[13 15 17]]]
============ sum axis=None=============
216
------------------
216
============ sum axis=0 =============
4 9 14
19 24 29
34 39 44
------------------
sum[0][0] = 4
sum[1][1] = 24
sum[2][2] = 44
------------------
[[ 4 9 14]
[19 24 29]
[34 39 44]]
============ sum axis=1 =============
12 15 18
24 30 36
21 27 33
------------------
sum[0][0] = 12
sum[1][1] = 30
sum[2][2] = 33
------------------
[[12 15 18]
[24 30 36]
[21 27 33]]
============ sum axis=2 =============
6 15 24
12 30 48
9 27 45
------------------
sum[0][0] = 6
sum[1][1] = 30
sum[2][2] = 45
------------------
[[ 6 15 24]
[12 30 48]
[ 9 27 45]]
============ sum axis=(0,1)) =============
57 72 87
------------------
sum[1] = 72
------------------
[57 72 87]
I want to transfer some weights trained by another network to TensorFlow, the weights are stored in a single vector like this:
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]
By using numpy, I can reshape it to two 3 by 3 filters like this:
1 2 3 9 10 11
3 4 5 12 13 14
6 7 8 15 16 17
Thus, the shape of my filters are (1,2,3,3). However, in TensorFlow, the shape of filters are (3,3,2,1):
tf_weights = tf.Variable(tf.random_normal([3,3,2,1]))
After reshaping the tf_weights to the expected shape, the weight becomes a mess and I can't get the expected convolution result.
To be specific, when the shape of an image or filter is [number,channel,size,size], I wrote a convolution function and it gives the correct answer,but it's too slow:
def convol(images,weights,biases,stride):
"""
Args:
images:input images or features, 4-D tensor
weights:weights, 4-D tensor
biases:biases, 1-D tensor
stride:stride, a float number
Returns:
conv_feature: convolved feature map
"""
image_num = images.shape[0] #the number of input images or feature maps
channel = images.shape[1] #channels of an image,images's shape should be like [n,c,h,w]
weight_num = weights.shape[0] #number of weights, weights' shape should be like [n,c,size,size]
ksize = weights.shape[2]
h = images.shape[2]
w = images.shape[3]
out_h = (h+np.floor(ksize/2)*2-ksize)/2+1
out_w = out_h
conv_features = np.zeros([image_num,weight_num,out_h,out_w])
for i in range(image_num):
image = images[i,...,...,...]
for j in range(weight_num):
sum_convol_feature = np.zeros([out_h,out_w])
for c in range(channel):
#extract a single channel image
channel_image = image[c,...,...]
#pad the image
padded_image = im_pad(channel_image,ksize/2)
#transform this image to a vector
im_col = im2col(padded_image,ksize,stride)
weight = weights[j,c,...,...]
weight_col = np.reshape(weight,[-1])
mul = np.dot(im_col,weight_col)
convol_feature = np.reshape(mul,[out_h,out_w])
sum_convol_feature = sum_convol_feature + convol_feature
conv_features[i,j,...,...] = sum_convol_feature + biases[j]
return conv_features
Instead, by using tensorflow's conv2d like this:
img = np.zeros([1,3,224,224])
img = img - 1
img = np.rollaxis(img, 1, 4)
weight_array = googleNet.layers[1].weights
weight_array = np.reshape(weight_array,[64,3,7,7])
biases_array = googleNet.layers[1].biases
tf_weight = tf.Variable(weight_array)
tf_img = tf.Variable(img)
tf_img = tf.cast(tf_img,tf.float32)
tf_biases = tf.Variable(biases_array)
conv_feature = tf.nn.bias_add(tf.nn.conv2d(tf_img,tf_weight,strides=[1,2,2,1],padding='SAME'),tf_biases)
sess = tf.Session()
sess.run(tf.initialize_all_variables())
feautre = sess.run(conv_feature)
The feature map I got is wrong.
Don't use np.reshape. It might mess up the order of your values.
Use np.rollaxis instead:
>>> a = np.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18])
>>> a = a.reshape((1,2,3,3))
>>> a
array([[[[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9]],
[[10, 11, 12],
[13, 14, 15],
[16, 17, 18]]]])
>>> b = np.rollaxis(a, 1, 4)
>>> b.shape
(1, 3, 3, 2)
>>> b = np.rollaxis(b, 0, 4)
>>> b.shape
(3, 3, 2, 1)
Note that the order of the two axes with size 3 haven't changed. If I were to label them, the two rollaxis operations caused the shapes to change as (1, 2, 31, 32) -> (1, 31, 32, 2) -> (31, 32, 2, 1). Your final array looks like:
>>> b
array([[[[ 1],
[10]],
[[ 2],
[11]],
[[ 3],
[12]]],
[[[ 4],
[13]],
[[ 5],
[14]],
[[ 6],
[15]]],
[[[ 7],
[16]],
[[ 8],
[17]],
[[ 9],
[18]]]])
Sample Tensor Manipulations
I dont know if this might be of help. Consider the Reshape ,Gather, Dynamic_partition and Split operations and adapt this to your needs.
In what comes below is the illustration of these operations that can be adapted to use in your situation. I copied this from my git repo. I will believe if you run this examples in ipython you can figure out what you really want and get even better insight.
Reshape ,Gather, Dynamic_partition and Split
Gather Operation ( tf.gather( ) )
Generate an array and test the gather operation. Note this approach for fast prototyping:
We generate an array in Numpy and test the operations of tensor flow on it.
Use: Gather slices from params according to indices.
indices must be an integer tensor of any dimension (usually 0-D or 1-D). This is best illustrated by an example:
array = np.array([[1,2,3],[4,9,6],[2,3,4],[7,8,0]])
array.shape
(4, 3)
In [27]:
gather_output0 = tf.gather(array,1)
gather_output01 = tf.gather(array,2)
gather_output02 = tf.gather(array,3)
gather_output11 = tf.gather(array,[1,2])
gather_output12 = tf.gather(array,[1,3])
gather_output13 = tf.gather(array,[3,2])
gather_output = tf.gather(array,[1,0,2])
gather_output1 = tf.gather(array,[1,1,2])
gather_output2 = tf.gather(array,[1,2,1])
In [28]:
with tf.Session() as sess:
print (gather_output0.eval());print("\n")
print (gather_output01.eval());print("\n")
print (gather_output02.eval());print("\n")
print (gather_output11.eval());print("\n")
print (gather_output12.eval());print("\n")
print (gather_output13.eval());print("\n")
print (gather_output.eval());print("\n")
print (gather_output1.eval());print("\n")
print (gather_output2.eval());print("\n")
#print (gather_output2.eval());print("\n")
[4 9 6]
[2 3 4]
[7 8 0]
[[4 9 6]
[2 3 4]]
[[4 9 6]
[7 8 0]]
[[7 8 0]
[2 3 4]]
[[4 9 6]
[1 2 3]
[2 3 4]]
[[4 9 6]
[4 9 6]
[2 3 4]]
[[4 9 6]
[2 3 4]
[4 9 6]]
And looking at this simple example:
Initialise simple array
test gather operation
In [11]:
array_simple = np.array([1,2,3])
In [15]:
print "shape of simple array is: ", array_simple.shape
shape of simple array is: (3,)
In [57]:
gather1 = tf.gather(array1,[0])
gather01 = tf.gather(array1,[1])
gather02 = tf.gather(array1,[2])
gather2 = tf.gather(array1,[1,2])
gather3 = tf.gather(array1,[0,1])
with tf.Session() as sess:
print (gather1.eval());print("\n")
print (gather01.eval());print("\n")
print (gather02.eval());print("\n")
print (gather2.eval());print("\n")
print (gather3.eval());print("\n")
[1]
[2]
[3]
[2 3]
[1 2]
tf.reshape( )
Note:
* Use the same array that was initiated
* Do reshape using tf.reshape( )
In [64]:
array.shape # Confirm array shape
Out[64]:
(4, 3)
In [74]:
print ("This is the array\n" ,array) # see the output and compare with the initial array,
This is the array
[[1 2 3]
[4 9 6]
[2 3 4]
[7 8 0]]
In [84]:
reshape_ops= tf.reshape(array,[-1,4]) # Note the parameters in reshpe
reshape_ops1= tf.reshape(array,[-1,3]) # Note the parameters in reshpe
reshape_ops2= tf.reshape(array,[-1,6]) # Note the parameters in reshpe
reshape_ops_back1= tf.reshape(array,[6,-1]) # Note the parameters in reshpe
reshape_ops_back2= tf.reshape(array,[3,-1]) # Note the parameters in reshpe
reshape_ops_back3= tf.reshape(array,[4,-1]) # Note the parameters in reshpe
In [86]:
with tf.Session() as sess:
print(reshape_ops.eval());print("\n")
print(reshape_ops1.eval());print("\n")
print(reshape_ops2.eval());print("\n")
print ("Output when we reverse the parameters:");print("\n")
print(reshape_ops_back1.eval());print("\n")
print(reshape_ops_back2.eval());print("\n")
print(reshape_ops_back3.eval());print("\n")
[[1 2 3 4]
[9 6 2 3]
[4 7 8 0]]
[[1 2 3]
[4 9 6]
[2 3 4]
[7 8 0]]
[[1 2 3 4 9 6]
[2 3 4 7 8 0]]
Output when we reverse the parameters:
[[1 2]
[3 4]
[9 6]
[2 3]
[4 7]
[8 0]]
[[1 2 3 4]
[9 6 2 3]
[4 7 8 0]]
[[1 2 3]
[4 9 6]
[2 3 4]
[7 8 0]]
Note: The input size and output size must be the same. ---otherwise it gives error. Simple way to check this out is to make sure the input can be paritioned into the the reshape parameters by doing simple multiplications.
Dynamic_cell_partitions
This is declared as :
tf.dynamic_partition (array, partitions, num_partitions, name=None)
Note:
* we decalare number_partitions --- number of partitions
* Use our array initialised earlier
* We declare the partition as [0 1 0 1] . This signifies the partitions we want 0's fall to one partition and 1 the other partitions given that we have two num_partitions=2.
* The output is a list
In [96]:
print ("This is the array\n" ,array) # This is output array
This is the array
[[1 2 3]
[4 9 6]
[2 3 4]
[7 8 0]]
We show how to make two and three partitions below
In [123]:
num_partitions = 2
num_partitions1 = 3
partitions = [0, 0, 1, 1]
partitions1 = [0 ,1 ,1, 2 ]
In [119]:
dynamic_ops =tf.dynamic_partition(array, partitions, num_partitions, name=None) # 2 partitions
dynamic_ops1 =tf.dynamic_partition(array, partitions1, num_partitions1, name=None) # 3 partitions
In [125]:
with tf.Session() as sess:
run = sess.run(dynamic_ops)
run1 = sess.run(dynamic_ops1)
print("Output for 2 partitions: ")
print (run[0]);print("\n")
print(run[1]) ;print("\n")# Compare result with initial array. Out is list
print("Output for three partitions: ")
print (run1[0]);print("\n")
print (run1[1]);print("\n")
print (run1[2]);print("\n")
Output for 2 partitions:
[[1 2 3]
[4 9 6]]
[[2 3 4]
[7 8 0]]
Output for three partitions:
[[1 2 3]]
[[4 9 6]
[2 3 4]]
[[7 8 0]]
tf.split( )
Make sure you use an up to date tensorflow version. Otherwise in older versions, this implemetation will give error
This is specified in the documentation as below:
tf.split(value, num_or_size_splits, axis=0, num=None, name='split').
It splits a tensor into subtensors. This is best illustrated by an example:
* we define (5,30) aray in numpy
* we split the array along axis 1
* We specify the number of splits as 1-Dimen Tensor along axis 1. So we have 3 splits.
Specify an array
Create a (5 by 30) numpy array. The syntax using numpy is shown below
In [2]:
ArrayBeforeSplitting = np.arange(150).reshape(5,30)
print ("Array shape without split operation is : " ,ArrayBeforeSplitting.shape)
('Array shape without split operation is : ', (5, 30))
specify number of splits
In [3]:
split_1D = tf.Variable([8,13,9])
print("specify number of partions using 1-Dimen Variable:" , tf.shape(split_1D))
('specify number of partions using 1-Dimen Variable:', <tf.Tensor 'Shape:0' shape=(1,) dtype=int32>)
Use tf.split
Make 3 splits aong y axis so that we have (5,8) ,(5,13),(5,9) splits. The axis 1 add up to give 30-- we can see axis 1 has 30 elements so the partition along that axis should add up to 30 otherwise it gives error.
In [6]:
split1,split2,split3 = tf.split(ArrayBeforeSplitting,split_1D,1)
# we have 3 splits along axis 1 specified spcifically
# by the split_1D . That is split axis 1D (with 30 elements) into partions with 8 ,13, and 9 elements while the x axis
#remains constant
In [7]:
#INitialise global variables. because split_ID is a variable and needs to be initialised before being
#used in a computational graph
init_op = tf.global_variables_initializer()
In [16]:
with tf.Session() as sess:
sess.run(init_op) # run variable initialisation.
result=split1.eval();print("\n")
print(result)
print("the shape of the first split operation is : ",result.shape)
result2=split2.eval();print("\n")
print(result2)
print("the shape of the second split operation is : ",result2.shape)
result3=split3.eval();print("\n")
print(result3)
print("the shape of the third split operation is : ",result3.shape)
[[ 0 1 2 3 4 5 6 7]
[ 30 31 32 33 34 35 36 37]
[ 60 61 62 63 64 65 66 67]
[ 90 91 92 93 94 95 96 97]
[120 121 122 123 124 125 126 127]]
('the shape of the first split operation is : ', (5, 8))
[[ 8 9 10 11 12 13 14 15 16 17 18 19 20]
[ 38 39 40 41 42 43 44 45 46 47 48 49 50]
[ 68 69 70 71 72 73 74 75 76 77 78 79 80]
[ 98 99 100 101 102 103 104 105 106 107 108 109 110]
[128 129 130 131 132 133 134 135 136 137 138 139 140]]
('the shape of the second split operation is : ', (5, 13))
Hope this helps!
I want to do a multidimensional array operation using numpy on three arrays, of which one is an index array, e.g.:
a = numpy.arange(20).reshape((5, 4))
# a = [[ 0 1 2 3] [ 4 5 6 7] [ 8 9 10 11] [12 13 14 15] [16 17 18 19]]
b = numpy.arange(24).reshape(((3, 2, 4)))
# b = [[[ 0 1 2 3] [ 4 5 6 7]] [[ 8 9 10 11] [12 13 14 15]] [[16 17 18 19] [20 21 22 23]]]
c = numpy.array([0,0,1,1,2])
# c = [0 0 1 1 2]
now, what I want is:
d = a * b[&] + b[&&]
where & is the second element of second dimension of b (e.g. [ 4 5 6 7]) and && is the first element of second dimension (e.g. [ 0 1 2 3]) related to i-th item of the first dimension of b, where i is from array c (e.g. c[0]=0 for the first element of first dimension of array b). d has same dimension as a.
Edit: Answer for the above example is:
# d = [[0 6 14 24] [16 26 38 52] [104 126 150 176] [152 178 206 236] [336 374 414 456]]
Thanks
>>> a * b[c,1,:] + b[c,0,:]
array([[ 0, 6, 14, 24],
[ 16, 26, 38, 52],
[104, 126, 150, 176],
[152, 178, 206, 236],
[336, 374, 414, 456]])
I have an image.
I want to obtain a 3x3 window (neighbouring pixels) for every pixel in the image.
I have this Python code:
for x in range(2,r-1,1):
for y in range(2,c-1,1):
mask5=numpy.array([cv.Get2D(copy_img,x-1,y-1),cv.Get2D(copy_img,x-1,y),cv.Get2D(copy_img,x-1,y+1),cv.Get2D(copy_img,x,y-1),cv.Get2D(copy_img,x,y),cv.Get2D(copy_img,x,y+1),cv.Get2D(copy_img,x+1,y-1),cv.Get2D(copy_img,x+1,y),cv.Get2D(copy_img,x+1,y+1)])
cent=[cv.Get2D(copy_img,x,y)]
mask5 is the 3x3 window. cent is the center pixel.
Is there a more efficient way to do this - i.e. using maps, iterators - anything but the two nested loops I've used?
This can be done faster, by reshaping and swapping axes, and then repeating over all kernel elements, like this:
im = np.arange(81).reshape(9,9)
print np.swapaxes(im.reshape(3,3,3,-1),1,2)
This gives you an array of 3*3 tiles which tessalates across the surface:
[[[[ 0 1 2] [[ 3 4 5] [[ 6 7 8]
[ 9 10 11] [12 13 14] [15 16 17]
[18 19 20]] [21 22 23]] [24 25 26]]]
[[[27 28 29] [[30 31 32] [[33 34 35]
[36 37 38] [39 40 41] [42 43 44]
[45 46 47]] [48 49 50]] [51 52 53]]]
[[[54 55 56] [[57 58 59] [[60 61 62]
[63 64 65] [66 67 68] [69 70 71]
[72 73 74]] [75 76 77]] [78 79 80]]]]
To get the overlapping tiles we need to repeat this 8 further times, but 'wrapping' the array, by using a combination of vstack and column_stack. Note that the right and bottom tile arrays wrap around (which may or may not be what you want, depending on how you are treating edge conditions):
im = np.vstack((im[1:],im[0]))
im = np.column_stack((im[:,1:],im[:,0]))
print np.swapaxes(im.reshape(3,3,3,-1),1,2)
#Output:
[[[[10 11 12] [[13 14 15] [[16 17 9]
[19 20 21] [22 23 24] [25 26 18]
[28 29 30]] [31 32 33]] [34 35 27]]]
[[[37 38 39] [[40 41 42] [[43 44 36]
[46 47 48] [49 50 51] [52 53 45]
[55 56 57]] [58 59 60]] [61 62 54]]]
[[[64 65 66] [[67 68 69] [[70 71 63]
[73 74 75] [76 77 78] [79 80 72]
[ 1 2 3]] [ 4 5 6]] [ 7 8 0]]]]
Doing it this way you wind up with 9 sets of arrays, so you then need to zip them back together. This, and all the reshaping generalises to this (for arrays where the dimensions are divisible by 3):
def new(im):
rows,cols = im.shape
final = np.zeros((rows, cols, 3, 3))
for x in (0,1,2):
for y in (0,1,2):
im1 = np.vstack((im[x:],im[:x]))
im1 = np.column_stack((im1[:,y:],im1[:,:y]))
final[x::3,y::3] = np.swapaxes(im1.reshape(rows/3,3,cols/3,-1),1,2)
return final
Comparing this new function to looping through all the slices (below), using timeit, its about 4 times faster, for a 300*300 array.
def old(im):
rows,cols = im.shape
s = []
for x in xrange(1,rows):
for y in xrange(1,cols):
s.append(im[x-1:x+2,y-1:y+2])
return s
I think the following does what you are after. The loop is only over the 9 elements. I'm sure there is a way of vectorizing it, but it's probably not worth the effort.
import numpy
im = numpy.random.randint(0,50,(5,7))
# idx_2d contains the indices of each position in the array
idx_2d = numpy.mgrid[0:im.shape[0],0:im.shape[1]]
# We break that into 2 sub arrays
x_idx = idx_2d[1]
y_idx = idx_2d[0]
# The mask is used to ignore the edge values (or indeed any values).
mask = numpy.ones(im.shape, dtype='bool')
mask[0, :] = False
mask[:, 0] = False
mask[im.shape[0] - 1, :] = False
mask[:, im.shape[1] - 1] = False
# We create and fill an array that contains the lookup for every
# possible 3x3 array.
idx_array = numpy.zeros((im[mask].size, 3, 3), dtype='int64')
# Compute the flattened indices for each position in the 3x3 grid
for n in range(0, 3):
for m in range(0, 3):
# Compute the flattened indices for each position in the
# 3x3 grid
idx = (x_idx + (n-1)) + (y_idx + (m-1)) * im.shape[1]
# mask it, and write it to the big array
idx_array[:, m, n] = idx[mask]
# sub_images contains every valid 3x3 sub image
sub_images = im.ravel()[idx_array]
# Finally, we can flatten and sort each sub array quickly
sorted_sub_images = numpy.sort(sub_images.reshape((idx[mask].size, 9)))
Try the following code as matlab function im2col(...)
import numpy as np
def im2col(Im, block, style='sliding'):
"""block = (patchsize, patchsize)
first do sliding
"""
bx, by = block
Imx, Imy = Im.shape
Imcol = []
for j in range(0, Imy):
for i in range(0, Imx):
if (i+bx <= Imx) and (j+by <= Imy):
Imcol.append(Im[i:i+bx, j:j+by].T.reshape(bx*by))
else:
break
return np.asarray(Imcol).T
if __name__ == '__main__':
Im = np.reshape(range(6*6), (6,6))
patchsize = 3
print Im
out = im2col(Im, (patchsize, patchsize))
print out
print out.shape
print len(out)