Reformatting a numpy array - python
I have come across some code (which may answer this question of mine). Here is the code (from Vivek Maskara's solution to my issue):
import cv2 as cv
import numpy as np
def read(image_path, label):
image = cv.imread(image_path)
image = cv.cvtColor(image, cv.COLOR_BGR2RGB)
image_h, image_w = image.shape[0:2]
image = cv.resize(image, (448, 448))
image = image / 255.
label_matrix = np.zeros([7, 7, 30])
for l in label:
l = l.split(',')
l = np.array(l, dtype=np.int)
xmin = l[0]
ymin = l[1]
xmax = l[2]
ymax = l[3]
cls = l[4]
x = (xmin + xmax) / 2 / image_w
y = (ymin + ymax) / 2 / image_h
w = (xmax - xmin) / image_w
h = (ymax - ymin) / image_h
loc = [7 * x, 7 * y]
loc_i = int(loc[1])
loc_j = int(loc[0])
y = loc[1] - loc_i
x = loc[0] - loc_j
if label_matrix[loc_i, loc_j, 24] == 0:
label_matrix[loc_i, loc_j, cls] = 1
label_matrix[loc_i, loc_j, 20:24] = [x, y, w, h]
label_matrix[loc_i, loc_j, 24] = 1 # response
return image, label_matrix
Would it be possible for you to explain how this part of the code works and what it specifically does:
if label_matrix[loc_i, loc_j, 24] == 0:
label_matrix[loc_i, loc_j, cls] = 1
label_matrix[loc_i, loc_j, 20:24] = [x, y, w, h]
label_matrix[loc_i, loc_j, 24] = 1 # response
I will first create and explain a simplified example, and then explain the part you pointed.
First, we create the ndarray named label_matrix:
import numpy as np
label_matrix = np.ones([2, 3, 4])
print(label_matrix)
This code means that you wil get an array containing 2 arrays, each of these 2 arrays will contain 3 arrays, and each of these 3 arrays will contain 4 elements.
And because we used np.ones, all these elements will have a value of 1.
So, printing label_matrix wil output this:
[[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]]
[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]]]
Now, we will change the values of first 4 elements of the first array contained by the first array of label_matrix.
To acces the first array of label_matrix, we do: label_matrix[0]
To access the first array contained by the first array of label_matrix we do: label_matrix[0, 0]
To access the first element of the first array contained by the first array of label_matrix we do: label_matrix[0, 0, 0]
To access the second element of the first array contained by the first array of label_matrix we do: label_matrix[0, 0, 1]
etc.
So, now, we will change the values of first 4 elements of the first array contained by the first array of label_matrix:
label_matrix[0, 0, 0] = 100
label_matrix[0, 0, 1] = 200
label_matrix[0, 0, 2] = 300
label_matrix[0, 0, 2] = 400
Output of label_matrix:
[[[100. 200. 300. 400.]
[ 1. 1. 1. 1.]
[ 1. 1. 1. 1.]]
[[ 1. 1. 1. 1.]
[ 1. 1. 1. 1.]
[ 1. 1. 1. 1.]]]
But we could have written it like this, instead of wrting 4 lines of codes:
label_matrix[0, 0, 0:4] = [100,200,300,400]
Writing label_matrix[0, 0, 0:4] means:
in the first array contained by the first array of label_matrix, select the 4 first elements (from index 0 to 4 (4 being not included))
So now you know the meaning of each line.
I'll explain the part of code you pointed:
if label_matrix[loc_i, loc_j, 24] == 0::
Test if the element at index 24 (the 23th element) has value 0
if yes, then:
label_matrix[loc_i, loc_j, cls] = 1:
assign the value 1 to the element at index cls. (If the variable named cls has value 4, it will assigne the value 1 to the element at index 4 of the first array contained by the first array of label_matrix)
label_matrix[loc_i, loc_j, 20:24] = [x, y, w, h]:
Say "x==100", "y==200", "w==300" and "h==400". So, in the first array contained by the first array of label_matrix, assign value 100 to the elemnt at index 20, value 200 to the elemnt at index 21, 300 at index 22 and 400 to index 23
label_matrix[loc_i, loc_j, 24] = 1:
in the first array contained by the first array of label_matrix, assign value 1 to the element at index 24
Related
How to round array of values based on new range?
i have an array of two value. What I'm trying to do is round those values to 0 or 1, but based on another "range", not the commom one of bigger than 0.5. For example, in the second elements, if the value is bigger than 0.6, the value changes to 1 and the other changes to 0. The array and the expected output are listed bellow: array = [[0.7 , 0.3 ], [0.4 , 0.6], [0.45, 0.55]] Expected array: array = [[1 , 0 ], [0 , 1], [1, 0]]
I think you can iterate through the array and change each value depending on this new threshold. threshold = 0.6 rows = len(array) cols = len(array[0]) for i in range(rows): for j in range(cols): if array[i][j] >= threshold: array[i][j] = 1 else: array[i][j] = 0
Numpy apply function to array
For example, I have function: f1 = lambda x: x % 2 If I want to modify array = np.linspace(0, 5, 6) I can do f1(array). Everything works as expected: [0. 1. 0. 1. 0. 1.] If I change function to: f2 = lambda x: 0 print(f2(array)) gives me 0 while I expected [0. 0. 0. 0. 0. 0.]. How to achieve consistency?
You can use below code to achieve desirable output import numpy as np array = np.linspace(0, 5, 6) f2 = lambda x: x-x print(f2(array))
Slightly more explicit than previous answer : import numpy as np array = np.linspace(0, 5, 6) f2 = lambda x: np.zeros_like(x) print(f2(array)) Documentation for numpy.zeros_like: Return an array of zeros with the same shape and type as a given array.
To iterate over an array, evaluate the function for every element, then store it to a resulting array, a list iterator works consistently: import numpy as np array = np.linspace(0, 5, 6) f1 = lambda x: x % 2 f2 = lambda x: 0 print ([f1(x) for x in array]) [0.0, 1.0, 0.0, 1.0, 0.0, 1.0] print ([f2(x) for x in array]) [0, 0, 0, 0, 0, 0]
How to get matrix rows by indexes?
Assuming that we have a matrix X and a target column y as following: import numpy as np X = np.ones([10,2]) for i in range(0,X.shape[0]): X[i][0] = i y = [0,1,2,1,0,0,1,2,3,3] I want to get rows of X depending on the value of y. From the small example above: For y == 0, I want to get rows of X as: [[0 1] [4 1] [5 1]] For y == 3, I want to get rows of X as: [[8 1] [9 1]] And so on. How can I solve this problem? I also tried print(X[y == 0][:]) But it did not work.
You must convert ordinary python array to numpy.ndarray, as follow Y=np.array(y) print(X[Y == 0][:]) you will get: [[ 0. 1.] [ 4. 1.] [ 5. 1.]]
Remove Decimals from Array
I have 2 arrays containing zeros & ones. I want to perform hstack() on them but not getting the desired output. Python Code.. import numpy as np zeros = np.zeros(8) ones = np.ones(8) zerosThenOnes = np.hstack((zeros, ones)) # A 1 by 16 array Current Output.. [ 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 1. 1. 1. 1. 1. 1.] Expected Output.. [ 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 ] I can't understand what silly mistake I'm doing.
You must tell numpy to return the values as integers import numpy as np zeros = np.zeros((8,), dtype=np.int) ones = np.ones((8,), dtype=np.int) zerosThenOnes = np.hstack((zeros, ones)) To print out zerosThenOnes like this [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1] Use: print([x for x in zerosThenOnes]) Numpy Zeros
np.hstack((np.zeros(8), np.ones(8))).astype(int) for np.array output, or map( int, np.hstack((np.zeros(8), np.ones(8))) ) for list output
Adding different sized/shaped displaced NumPy matrices
In short: I have two matrices (or arrays): import numpy block_1 = numpy.matrix([[ 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0]]) block_2 = numpy.matrix([[ 1, 1, 1], [ 1, 1, 1], [ 1, 1, 1], [ 1, 1, 1]]) I have the displacement of block_2 in the block_1 element coordinate system. pos = (1,1) I want to be able to add them (quickly), to get: [[0 0 0 0 0] [0 1 1 1 0] [0 1 1 1 0] [0 1 1 1 0]] In long: I would like a fast way to add two different shape matrices together, where one of the matrices can be displaced. The resulting matrix must have the shape of the first matrix, and the overlapping elements between the two matrices are summed. If there is no overlap, just the first matrix is returned unmutated. I have a function that works fine, but it's kind of ugly, and elementwise: def add_blocks(block_1, block_2, pos): for i in xrange(0, block_2.shape[0]): for j in xrange(0, block_2.shape[1]): if (i + pos[1] >= 0) and (i + pos[1] < block_1.shape[0]) and (j + pos[0] >= 0) and (j + pos[0] < block_1.shape[1]): block_1[pos[1] + i, pos[0] + j] += block_2[i,j] return block_1 Can broadcasting or slicing perhaps do this? I feel like maybe I'm missing something obvious.
An easy solution that looks like MATLAB solution is: import numpy as np block1 = np.zeros((5,4)) block2 = np.ones((3,2)) block1[1:4,2:4] += block2 # use array slicing print(block1) [[0. 0. 0. 0.] [0. 0. 1. 1.] [0. 0. 1. 1.] [0. 0. 1. 1.] [0. 0. 0. 0.]] So package it as a reusable function: import numpy as np def addAtPos(mat1, mat2, xypos): """ Add two matrices of different sizes in place, offset by xy coordinates Usage: - mat1: base matrix - mat2: add this matrix to mat1 - xypos: tuple (x,y) containing coordinates """ x, y = xypos ysize, xsize = mat2.shape xmax, ymax = (x + xsize), (y + ysize) mat1[y:ymax, x:xmax] += mat2 return mat1 block1 = np.zeros((5,4)) block2 = np.ones((3,2)) pos = (2,1) print(addAtPos(block1, block2, pos)) [[0. 0. 0. 0.] [0. 0. 1. 1.] [0. 0. 1. 1.] [0. 0. 1. 1.] [0. 0. 0. 0.]]
You just have to find the overlapping range, and then add the arrays using slicing. b1 = np.zeros((4,5)) b2 = np.ones((4,3)) pos_v, pos_h = 2, 3 # offset v_range1 = slice(max(0, pos_v), max(min(pos_v + b2.shape[0], b1.shape[0]), 0)) h_range1 = slice(max(0, pos_h), max(min(pos_h + b2.shape[1], b1.shape[1]), 0)) v_range2 = slice(max(0, -pos_v), min(-pos_v + b1.shape[0], b2.shape[0])) h_range2 = slice(max(0, -pos_h), min(-pos_h + b1.shape[1], b2.shape[1])) b1[v_range1, h_range1] += b2[v_range2, h_range2] They're added in-place, but you could also create a new array. I might have missed some corner cases, though, but it seems to work fine.
Here's #jorgeca's great code as a function, with some tests - I expanded the slices to try to make it a little more readable: import numpy as np def addAtPos(matrix1, matrix2, xypos, inPlace=False): """ Add matrix2 into matrix1 at position xypos (x,y), in-place or in new matrix. Handles matrix2 going off edges of matrix1. """ x, y = xypos h1, w1 = matrix1.shape h2, w2 = matrix2.shape # get slice ranges for matrix1 x1min = max(0, x) y1min = max(0, y) x1max = max(min(x + w2, w1), 0) y1max = max(min(y + h2, h1), 0) # get slice ranges for matrix2 x2min = max(0, -x) y2min = max(0, -y) x2max = min(-x + w1, w2) y2max = min(-y + h1, h2) if inPlace: # add matrix2 into matrix1, in place matrix1[y1min:y1max, x1min:x1max] += matrix2[y2min:y2max, x2min:x2max] else: # create and return a new matrix matrix1copy = matrix1.copy() matrix1copy[y1min:y1max, x1min:x1max] += matrix2[y2min:y2max, x2min:x2max] return matrix1copy def test_addAtPos(): matrix1 = np.zeros((2,2)) matrix2 = np.ones((2,2)) test(addAtPos(matrix1, matrix2, ( 0, 0)), [[1,1],[1,1]]) test(addAtPos(matrix1, matrix2, ( 2, 2)), [[0,0],[0,0]]) test(addAtPos(matrix1, matrix2, (-1,-1)), [[1,0],[0,0]]) test(addAtPos(matrix1, matrix2, ( 1,-1)), [[0,1],[0,0]]) test(addAtPos(matrix1, matrix2, ( 1, 1)), [[0,0],[0,1]]) test(addAtPos(matrix1, matrix2, (-1, 1)), [[0,0],[1,0]]) def test(actual, expected, message=''): "Compare actual and expected values and print OK or FAIL" passed = (actual == expected) if type(passed) == np.ndarray: passed = passed.all() actual = str(actual).replace('\n', '') expected = str(expected).replace('\n', '') if passed: print('[OK] ', message, actual) else: print('[FAIL]', message, actual, ' != expected value of', expected) test_addAtPos() Output: [OK] [[1. 1.] [1. 1.]] [OK] [[0. 0.] [0. 0.]] [OK] [[1. 0.] [0. 0.]] [OK] [[0. 1.] [0. 0.]] [OK] [[0. 0.] [0. 1.]] [OK] [[0. 0.] [1. 0.]]
This is great, and here's how to extend the addition to a 3D matrix by adding a few lines to jorgeca's code: import numpy as np #two 3d arrays, of different size. b1 = np.zeros((5,5,5), dtype=np.int) # a 5x5x5 matrix of zeroes b2 = np.ones((3,3,3), dtype=np.int) # a 3x3x3 matrix of ones pos_v, pos_h, pos_z = 2, 2, 2 # a 3d offset -> to plonk b2 in the corner of b1 v_range1 = slice(max(0, pos_v), max(min(pos_v + b2.shape[0], b1.shape[0]), 0)) h_range1 = slice(max(0, pos_h), max(min(pos_h + b2.shape[1], b1.shape[1]), 0)) z_range1 = slice(max(0, pos_z), max(min(pos_z + b2.shape[2], b1.shape[2]), 0)) v_range2 = slice(max(0, -pos_v), min(-pos_v + b1.shape[0], b2.shape[0])) h_range2 = slice(max(0, -pos_h), min(-pos_h + b1.shape[1], b2.shape[1])) z_range2 = slice(max(0, -pos_z), min(-pos_z + b1.shape[2], b2.shape[2])) b1[v_range1, h_range1, z_range1] += b2[v_range2, h_range2, z_range2] This might help someone who wants to do the same in 3d (like me).
I'm sure there is a fast NumPy way to do this, but there is a more efficient way to do it even in normal Python: block_1 = [ [ 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0]] block_2 = [ [ 1, 1, 1], [ 1, 1, 1], [ 1, 1, 1], [ 1, 1, 1]] pos = (1, 1) x, y = pos # width of the rows in block_2 length = len(block_2[0]) # skip the first y rows for row_1, row_2 in zip(block_1[y:], block_2): # set length elements offset by x to the sum. row_1[x:length + x] = map(sum, zip(row_2, row_1[x:length + x])) print '\n'.join(' '.join(map(str, row)) for row in block_1) """ 0 0 0 0 0 0 1 1 1 0 0 1 1 1 0 0 1 1 1 0 """