Calculating area of polygon bounding boxes - python

I'm trying to calculate area of polygon bounding boxes and the coordinates (x and y of polygon vertices) are saved in mask variable. This is my code:
f = open('train_labels.json')
data = json.load(f)
mask = []
for i in data.keys(): # iterate over all images in dataset
for j in data[i]: # iterate over json to access points (coordinates)
mask.append(j['points'])
print(mask)
area = (mask[:, 3] - mask[:, 1]) * (mask[:, 2] - mask[:, 0])
print(area)
Error that shows me is: TypeError: list indices must be integers or slices, not tuple
When I print mask, the output is:
[[[141, 199], [237, 201], [313, 236], [357, 283], [359, 300], [309, 261], [233, 230], [140, 231]], [[25, 13], [57, 71], [26, 92], [0, 34]], [[264, 21], [296, 0], [300, 9], [272, 31]], [[322, 0], [351, 25], [340, 31], [317, 9]]] [[[141, 199], [237, 201], [313, 236], [357, 283], [359, 300], [309, 261], [233, 230], [140, 231]], [[25, 13], [57, 71], [26, 92], [0, 34]], [[264, 21], [296, 0], [300, 9], [272, 31]], [[322, 0], [351, 25], [340, 31], [317, 9]], [[287, 71]]] etc...
So between tripple square brackets ...,[317, 9]]] [[[141, 199],... doesn't exist comma (,) and is that the problem? If is how can I solve this?

Try:
xy = list(zip(*mask[-1]))
area = (max(xy[0])-min(xy[0]))*(max(xy[1])-min(xy[1]))
mask[-1] will get the last item appended to mask (if you need the mask storing all the items).
xy is a two element list with all x-coordinates in first element and all y-coordinates of the polygon in second element.
area of the bounding box goes respectively from min, to max of x and y coordinates. The 'polygon' can have any number of points, but at least one.
I suggest you choose another name for mask as the name 'mask' suggest a use as mask which is not the case. For example polygons_points_xy will better express what value is represented by the name.

Related

How to find the smallest value of element in matrix with size (9,2,2)

Supposing I have a matrix A with the np.shape(A) = (9,2,2).
Then, I would like to find the smallest element value for the inner matrix (2,2) of total 9 outer matrix. Let's call it B.
Could anyone let me know what is the numpy code, please?
Thank you in advance.
import numpy as np
A =np.array([[[24, 73],
[35, 67]],
[[35, 68],
[21, 5]],
[[29, 69],
[60, 46]],
[[98, 25],
[50, 92]],
[[63, 27],
[55, 28]],
[[60, 89],
[61, 66]],
[[87, 38],
[44, 33]],
[[64, 76],
[76, 70]],
[[90, 91],
[71, 58]]])
np.shape(A)
Expected Result
B = [24,5,29,25,27,60,38,64,58]
np.shape(B) = (9,)
Solution
import numpy as np
A =np.array([[[24, 73],
[35, 67]],
[[35, 68],
[21, 5]],
[[29, 69],
[60, 46]],
[[98, 25],
[50, 92]],
[[63, 27],
[55, 28]],
[[60, 89],
[61, 66]],
[[87, 38],
[44, 33]],
[[64, 76],
[76, 70]],
[[90, 91],
[71, 58]]])
B1 = A.min(axis=(1, 2))
B2 = np.min(A, axis=(1, 2))
print("B1 =", B1)
print("B2 =", B2)
print("np.shape(B1) =", np.shape(B1))
Find minimum value with 2 menthods
1.
B1 = A.min(axis=(1, 2))
2.
B2 = np.min(A, axis=(1, 2))
Find shape of array in numpy
shape = np.shape(B1)
Output
B1 = [24 5 29 25 27 60 33 64 58]
B2 = [24 5 29 25 27 60 33 64 58]
np.shape(B1) = (9,)
Use min aggregating on the last two axes:
A.min((1, 2))
Alternatively, if you want a generic code to handle any number of dimensions, reshape then aggregate the min on the last dimension:
A.reshape(A.shape[0], -1).min(-1)
Output: array([24, 5, 29, 25, 27, 60, 33, 64, 58])
Since you wish only the get the code, there you go:
np.min(A, axis=(1,2))

Numpy: How to calculate sums of array slices using indeces?

I have a matrix M:
M = [[10, 1000],
[11, 200],
[15, 800],
[20, 5000],
[28, 100],
[32, 3000],
[35, 3500],
[38, 100],
[50, 5000],
[51, 100],
[55, 2000],
[58, 3000],
[66, 4000],
[90, 5000]]
And a matrix R:
[[10 20]
[32 35]
[50 66]
[90 90]]
I want to use the values in column 0 of matrix R as start value of a slice and the value in column 1 as end of a slice.
I want to calculate the sum between and including the ranges of these slices from the right column in matrix M.
Basically doing
M[0:4][:,1].sum() # Upper index +1 as I need upper bound including
M[5:7][:,1].sum() # Upper index +1 as I need upper bound including
and so on. 0 is the index of 10 and 3 is the index of 20. 5 would be the index of 32, 6 the index of 35.
I'm stuck at how to get the start/end values from matrix R into indeces by column 0 of matrix M. And then calculate the sum between the index range including upper/lower bound.
Expected output:
[[10, 20, 7000], # 7000 = 1000+200+800+5000
[32, 35, 6500], # 6500 = 3000+3500
[50, 66, 14100], # 14100 = 5000+100+2000+3000+4000
[90, 90, 5000]] # 5000 = just 5000 as upper=lower boundary
Update, I can get the indices now using searchsorted. Now I just need to use sum at column 1 of matrix M within the start and end.
start_indices = [0,5,8,13]
end_indices = [3,6,12,13]
Wondering if there is a more efficient way than applying a for loop?
EDIT: Found the answer here. Numpy sum of values in subarrays between pairs of indices
Use searchsorted to determine the correct indices and add.reduceat to perform the summation:
>>> idx = M[:, 0].searchsorted(R) + (0, 1)
>>> idx = idx.ravel()[:-1] if idx[-1, 1] == M.shape[0] else idx.ravel()
>>> result = np.add.reduceat(M[:, 1], idx)[::2]
>>> result
array([ 7000, 6500, 14100, 5000])
Details:
Since you want to include the upper boundaries but Python excludes them we have to add 1.
reduceat cannot handle len(arg0) as an index, we have to special case that
reduceat computes all stretches between consecutive boundaries, we have to discard every other one
I think it would be better to show an example of the output you are expecting. If what you want to calculate using M[0:4][:,1].sum() is the sum of 1000 + 200 + 800 + 5000. Then this code might help:
import numpy as np
M = np.matrix([[10, 1000],
[11, 200],
[15, 800],
[20, 5000],
[28, 100],
[32, 3000],
[35, 3500],
[38, 100],
[50, 5000],
[51, 100],
[55, 2000],
[58, 3000],
[66, 4000],
[90, 5000]])
print(M[0:4][:,1].sum())

How to add a list to lists within a list, to create lists within lists within a list?

Pretty new to Python so if the title isn't confusing enough, I'd appreciate some help. I will able to best explain this using an example of what I'm aiming to achieve.
Number = [25, 30, 36]
Ratings = [ [101, 201, 301], [102, 202, 302], [103, 203, 304,] ]
what_i_want = [ [ [101, 25],[201,30],[301,36] ], [ [102,25],[202,25],[302,36] ], [ [103,25],[203,30],[303,36] ] ]
I'm completely stumped on how to do this, I've tried using nested for loops but the list ends up looking like this:
list = [ ([101, 201, 301], 25), ([102, 202, 302], 30), ([103, 203, 304,], 36) ]
Also, I'm going to be dealing with a very large size of lists, so ways to improve efficiency and speed would also be very helpful.
You can use zip with list comprehension:
Number = [25, 30, 36]
Ratings = [ [101, 201, 301], [102, 202, 302], [103, 203, 304,] ]
new_data = [[[a, b] for a, b in zip(i, Number)] for i in Ratings]
Output:
[[[101, 25], [201, 30], [301, 36]], [[102, 25], [202, 30], [302, 36]], [[103, 25], [203, 30], [304, 36]]]
You can use nested for loops as such.
Number = [25, 30, 36]
Ratings = [ [101, 201, 301], [102, 202, 302], [103, 203, 304,] ]
list = []
for i in xrange(len(Ratings)): #Iterate through outer list.
list.append([]) #Add new middle list to list.
for j in xrange(len(Ratings[i])): #Iterate through inner list.
list[i].append([Ratings[i][j],Number[j]])
Output:
list = [[[101, 25], [201, 30], [301, 36]], [[102, 25], [202, 30], [302, 36]], [[103, 25], [203, 30], [304, 36]]]
You can do in one line without importing any module or making it more complex :
just use lambda :
Number = [25, 30, 36]
Ratings = [ [101, 201, 301], [102, 202, 302], [103, 203, 304,] ]
print(list(map(lambda x:list(map(lambda y,y1:[y,y1],x,Number)),Ratings)))
output:
[[[101, 25], [201, 30], [301, 36]], [[102, 25], [202, 30], [302, 36]], [[103, 25], [203, 30], [304, 36]]]

Merge equally sized arrays into tiled big array

I'm having a hard time phrasing what I want, which is why I didn't find it on Google. Let me start with an example before formulating the general case.
Say we have 7 arrays a1, ..., a7, each of shape (4, 5). I want a new array where the 7 arrays are arranged like this:
a1 a2 a3
a4 a5 a6
a7 0 0
This array is of shape (3*4, 3*5) == (12, 15), 0 is np.zeros((4, 5)).
In general, I have C arrays a1, ..., aC, of shape (H, W), and I want to put them into an array of shape (h*H, w*W), where h = ceil(sqrt(C)) and w = ceil(C/h). The C arrays are stored as one (C, H, W) dimensional array.
What's the most elegant way to do this? I was hacking something together by iterating over the necessary indices but it's not nice so I stopped.
Speed is not top priority and the arrays are fairly small.
Approach #1
Some permuting of axes and reshaping should do the job -
C,m,n = a.shape
h = int(np.ceil(np.sqrt(C)))
w = int(np.ceil(C/h))
out = np.zeros((h,w,m,n),dtype=a.dtype)
out.reshape(-1,m,n)[:C] = a
out = out.swapaxes(1,2).reshape(-1,w*n)
Sample input, output -
In [340]: a
Out[340]:
array([[[55, 58],
[75, 78]],
[[78, 20],
[94, 32]],
[[47, 98],
[81, 23]],
[[69, 76],
[50, 98]],
[[57, 92],
[48, 36]],
[[88, 83],
[20, 31]],
[[91, 80],
[90, 58]]])
In [341]: out
Out[341]:
array([[55, 58, 78, 20, 47, 98],
[75, 78, 94, 32, 81, 23],
[69, 76, 57, 92, 88, 83],
[50, 98, 48, 36, 20, 31],
[91, 80, 0, 0, 0, 0],
[90, 58, 0, 0, 0, 0]])
Approach #2
Simpler one with zeros-concatenation -
z = np.zeros((h*w-C,m,n),dtype=a.dtype)
out = np.concatenate((a,z)).reshape(h,w,m,n).swapaxes(1,2).reshape(-1,w*n)
That could be modified/simplified a bit by using zeros-padding with np.pad -
zp = np.pad(a,((0,h*w-C),(0,0),(0,0)),'constant')
out = zp.reshape(h,w,m,n).swapaxes(1,2).reshape(-1,w*n)

Separating 3-d array into 2-d arrays along the respective columns

temp1 = tempObj[0][0]
temp2 = tempObj[0][1]
if len(tempObj) > 1:
for i in range(1, len(tempObj)):
temp1 = np.vstack((temp1, tempObj[i][0]))
temp2 = np.vstack((temp2, tempObj[i][1]))
The code is in Python. In the above code, I am trying to separate the numpy 3-d array (tempObj) into two 2-d arrays (temp1 & temp2) so that the respective columns are merged.
Is there a better or simpler way to do this?
use tempObj[:, 0, :] and tempObj[:, 1, :]. here is an example:
import numpy as np
tempObj = np.array([
[
[1,5], [2,7], [3,8], [4,4],
[6, 5], [4, 7], [13, 8], [9, 4]
],
[
[21,25], [22,72], [32,82], [34,43],
[64, 54], [44, 74], [1443, 48], [94, 44]
],
[
[211, 215], [212, 712], [312, 812], [314, 413],
[614, 514], [414, 714], [11443, 148], [194, 414]
]
])
# Your code:
############################################
temp1 = tempObj[0][0]
temp2 = tempObj[0][1]
if len(tempObj) > 1:
for i in range(1, len(tempObj)):
temp1 = np.vstack((temp1, tempObj[i][0]))
temp2 = np.vstack((temp2, tempObj[i][1]))
print(temp1)
print(temp2)
# my suggestion
############################################
print(tempObj[:, 0, :])
print(tempObj[:, 1, :])
You need to make sure that the type of tempObj (or any part of it) is numpy.ndarray and not list. You can do it by typing print(type(tempObj)). The following example is what I suspect that is your code that gives an error of TypeError: list indices must be integers, not tuple:
tempObj = [
np.array([
[1,5], [2,7], [3,8], [4,4],
[6, 5], [4, 7], [13, 8], [9, 4]
]),
np.array([
[21,25], [22,72], [32,82], [34,43],
[64, 54], [44, 74], [1443, 48], [94, 44]
]),
np.array([
[211, 215], [212, 712], [312, 812], [314, 413],
[614, 514], [414, 714], [11443, 148], [194, 414]
])
]

Categories

Resources