Related
I have an 2-D array that I want to find the max value per row and then find the next max-value that is not within +/- n of the previous value. For example I have the following matrix:
results =
array([[ 33, 108, 208, 96, 96, 112, 18, 208, 33, 323, 60, 42],
[ 51, 6, 39, 112, 160, 144, 342, 195, 27, 136, 42, 54],
[ 12, 176, 266, 162, 45, 70, 156, 198, 143, 56, 342, 130],
[ 22, 288, 304, 162, 21, 238, 156, 126, 165, 91, 144, 130],
[342, 120, 36, 51, 10, 128, 156, 272, 32, 98, 192, 288]])
row_max_index = results.argmax(1)
row_max_index #show max index
array([ 9, 6, 10, 2, 0])
Now I'd like to get the next max value not within say +/- 2 of the current max.
Here is what I have but it feels sloppy:
maskIndx = np.c_[row_max_index-2, row_max_index-1, row_max_index, row_max_index+1, row_max_index+2,]%12
maskIndx #show windowed index
array([[ 7, 8, 9, 10, 11],
[ 4, 5, 6, 7, 8],
[ 8, 9, 10, 11, 0],
[ 0, 1, 2, 3, 4],
[10, 11, 0, 1, 2]])
results[np.meshgrid(np.arange(5), np.arange(5))[1], maskIndx] = 0 #uses array indexing
results #show results
array([[ 33, 108, 208, 96, 96, 112, 18, 0, 0, 0, 0, 0],
[ 51, 6, 39, 112, 0, 0, 0, 0, 0, 136, 42, 54],
[ 0, 176, 266, 162, 45, 70, 156, 198, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 238, 156, 126, 165, 91, 144, 130],
[ 0, 0, 0, 51, 10, 128, 156, 272, 32, 98, 0, 0]])
next_max_index = results.argmax(1)
array([2, 9, 2, 5, 7])
Any ideas on doing this faster through indexing/windowing?
You can create a mask around the indices you compute for the max by taking an array of indices and subtracting the relevant max_indices, and then use the masked api to recompute the argmax:
import numpy as np
result = ... # Result here
row_max_index = results.argmax(axis=1, keepdims=True)
indices = np.arange(results.shape[1])
mask = np.abs(indices - row_max_index) <= 2
out = np.ma.array(results, mask=mask).argmax(axis=1)
I have two lists and I would like to calculate the permutations between the two. I have been able to successfully do this using itertools, but am having trouble taking it further.
I have two nested lists:
list_1 = [0, 226, 68, 100, 70, 71, 42, 43, 44, 14, 16, 114, 210, 22, 87, 28, 125][10, 216, 67, 120, 70, 717, 42, 43, 445, 14, 87, 289, 125]
list_2 = [10, 9, 2, 1, 0][10, 216, 7, 10, 70, 717, 42, 3, 445, 14, 162, 87, 289, 125]
The first entry of list_1 ([0, 226, 68, 100, 70, 71, 42, 43, 44, 14, 16, 114, 210, 22, 87, 28, 125]) needs to be permutated with the first entry of list_2 ([10, 9, 2, 1, 0]). Then I need to get the permutations of the second entry of list_1 with the second entry of list_2, etc.
The issue is that there will be no set number of entries in each list, so it is not feasible to simply make variables for list_1[0], list_2[0], etc.
What would be the simplest way to do this?
import itertools
list_1 = ([0, 226, 68, 100, 70, 71, 42, 43, 44, 14, 16, 114, 210, 22, 87, 28, 125],
[10, 216, 67, 120, 70, 717, 42, 43, 445, 14, 87, 289, 125])
list_2 = ([10, 9, 2, 1, 0],
[10, 216, 7, 10, 70, 717, 42, 3, 445, 14, 162, 87, 289, 125])
count = 0
for list1_item, list2_item in zip(list_1, list_2):
print(f"{list1_item=} {list2_item=}")
for permutation in itertools.permutations(itertools.chain(list1_item, list2_item)):
if count % 10**8 == 0: # print once in a while
print(permutation)
count += 1
print(count)
print(f"last permutation: {permutation}")
gives
list1_item=[0, 226, 68, 100, 70, 71, 42, 43, 44, 14, 16, 114, 210, 22, 87, 28, 125] list2_item=[10, 9, 2, 1, 0]
(0, 226, 68, 100, 70, 71, 42, 43, 44, 14, 16, 114, 210, 22, 87, 28, 125, 10, 9, 2, 1, 0)
(0, 226, 68, 100, 70, 71, 42, 43, 44, 14, 210, 125, 10, 9, 114, 22, 0, 87, 2, 1, 16, 28)
(0, 226, 68, 100, 70, 71, 42, 43, 44, 14, 28, 16, 210, 22, 125, 9, 1, 2, 87, 10, 114, 0)
...
list1_item=[10, 216, 67, 120, 70, 717, 42, 43, 445, 14, 87, 289, 125] list2_item=[10, 216, 7, 10, 70, 717, 42, 3, 445, 14, 162, 87, 289, 125]
(10, 216, 67, 120, 70, 717, 42, 43, 445, 14, 87, 289, 125, 10, 216, 7, 10, 70, 717, 42, 3, 445, 14, 162, 87, 289, 125)
...
[0,
100,
7,
27,
34,
40,
41,
48,
58,
65,
75,
78,
79,
96,
126,
127,
0,
0,
2,
45,
54,
56,
57,
59,
66,
67,
82,
86,
102,
124,
133,
0,
0,
35,
39,
52,
53,
60,
61,
80,
81,
83,
87,
97,
98,
101,
109,
0,
0,
15,
28,
29,
30,
31,
32,
33,
37,
38,
49,
50,
51,
71,
95,
0,
0,
3,
16,
22,
23,
44,
72,
73,
74,
90,
110,
131,
0,
0,
10,
11,
18,
19,
36,
55,
89,
93,
94,
108,
113,
114,
0,
0,
1,
5,
6,
9,
12,
17,
24,
43,
64,
77,
85,
88,
91,
92,
111,
112,
130,
0,
0,
13,
20,
42,
62,
68,
84,
99,
104,
116,
119,
125,
128,
129,
132,
0,
0,
8,
14,
26,
63,
69,
70,
103,
105,
123,
0,
0,
4,
21,
25,
46,
47,
106,
107,
115,
117,
118,
120,
121,
122,
0,
0,
76,
0]
I have this list of values and I want to split is between every two zeroes.
So my list will look like this:
[0, 100, 7, 27, 34, 40, 41, 48, 58, 65, 75, 78, 79, 96, 126, 127, 0],[ 0, 2, 45, 54, 56, 57, 59, 66, 67, 82, 86, 102, 124, 133, 0],[ 0, 35, 39, 52, 53, 60, 61, 80, 81, 83, 87, 97, 98, 101, 109, 0],[ 0, 15, 28, 29, 30, 31, 32, 33, 37, 38, 49, 50, 51, 71, 95, 0],[ 0, 3, 16, 22, 23, 44, 72, 73, 74, 90, 110, 131, 0][ 0, 10, 11, 18, 19, 36, 55, 89, 93, 94, 108, 113, 114, 0],[ 0, 1, 5, 6, 9, 12, 17, 24, 43, 64, 77, 85, 88, 91, 92, 111, 112, 130, 0],[ 0, 13, 20, 42, 62, 68, 84, 99, 104, 116, 119, 125, 128, 129, 132, 0],[ 0, 8, 14, 26, 63, 69, 70, 103, 105, 123, 0],[ 0, 4, 21, 25, 46, 47, 106, 107, 115, 117, 118, 120, 121, 122, 0][ 0, 76, 0]
Can someone help me out?
you may use a simple for loop with the built-in function zip:
# l is your list
result = [[l[0]]]
for i, j in zip(l[1:], l):
if i == 0 == j:
result.append([i])
else:
result[-1].append(i)
result
output:
[[0, 100, 7, 27, 34, 40, 41, 48, 58, 65, 75, 78, 79, 96, 126, 127, 0],
[0, 2, 45, 54, 56, 57, 59, 66, 67, 82, 86, 102, 124, 133, 0],
[0, 35, 39, 52, 53, 60, 61, 80, 81, 83, 87, 97, 98, 101, 109, 0],
[0, 15, 28, 29, 30, 31, 32, 33, 37, 38, 49, 50, 51, 71, 95, 0],
[0, 3, 16, 22, 23, 44, 72, 73, 74, 90, 110, 131, 0],
[0, 10, 11, 18, 19, 36, 55, 89, 93, 94, 108, 113, 114, 0],
[0, 1, 5, 6, 9, 12, 17, 24, 43, 64, 77, 85, 88, 91, 92, 111, 112, 130, 0],
[0, 13, 20, 42, 62, 68, 84, 99, 104, 116, 119, 125, 128, 129, 132, 0],
[0, 8, 14, 26, 63, 69, 70, 103, 105, 123, 0],
[0, 4, 21, 25, 46, 47, 106, 107, 115, 117, 118, 120, 121, 122, 0],
[0, 76, 0]]
I think the easiest way is to do this:
outputList=[]
start = 0
for i in range(len(myList) - 1):
curr = myList[i]
next = myList[i+1]
if curr == 0 and next == 0:
outputList.append(myList[start:i+1]
start = i+1
I think that will do the job, let me now if that worked! :D
I'm a real starter in machine learning. But I'm trying to deploy the MNIST character recognition example with a Flask server. I already set up the model, trained it and set up Flask.
I've created a simple HTML canvas where I can draw numbers from 0-9. These are sent via AJAX to my python backend.
In the Python backend, I receive the Base64 Image and decode it to a 255-grayscale array. So I have this giant array with information about the image:
[138, 102, 160, 120, 54, 173, 105, 214, 173, 106, 41, 154, 129, 239, 233, 158, 6, 218, 177, 238, 184, 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 1, 144, 0, 0, 1, 144, 8, 6, 0, 0, 0, 128, 191, 54, 204, 0, 0, 28, 81, 73, 68, 65, 84, 120, 94, 237, 221, 9, 172, 109, 87, 89, 7, 240, 63, 145, 72, 152, 154, 128, 128, 168, 16, 32, 21, 80, 169, 80, 202, 148, 20, 16, 43, 161, 45, 80, 160, 140, 50, 180, 34, 29, 24, 210, 42, 2, 130, 180, 1, 25, 211, 34, 163, 96, 27, 134, 14, 32, 101, 146, 25, 139, 165, 45, 40, 164, 12, 134, 22, 104, 9, 160, 76, 13, 40, 168, 164, 32, 36, 101, 10, 4, 131, 89, 118, 95, 122, 237, 240, 222, 121, 251, 158, 179, 246, 218, 107, 255, 78, 242, 114, 31, 183, 103, 237, 181, 190, 223, 183, 30, 255, 220, 187, 207, 222, 251, 26, 241, 34, 64, 128, 0, 1, 2, 35, 4, 174, 49, 98, 140, 33, 4, 8, 16, 32, 64, 32, 2, 196, 38, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30]
But I can't find a way to reshape this array so I can feed it into my tensorflow model, which requires the following input:
Tensor("shape=(28, 28, 1), dtype=float32)
Can you help me find a way to transform this array in Python to a tensor of appropriate size?
Thanks already
Here is some code that should work.
import numpy as np
import tensorflow as tf
data = [138, 102, 160, 120, 54, 173, 105, 214, 173, 106, 41, 154, 129, 239, 233, 158, 6, 218, 177, 238, 184, 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 1, 144, 0, 0, 1, 144, 8, 6, 0, 0, 0, 128, 191, 54, 204, 0, 0, 28, 81, 73, 68, 65, 84, 120, 94, 237, 221, 9, 172, 109, 87, 89, 7, 240, 63, 145, 72, 152, 154, 128, 128, 168, 16, 32, 21, 80, 169, 80, 202, 148, 20, 16, 43, 161, 45, 80, 160, 140, 50, 180, 34, 29, 24, 210, 42, 2, 130, 180, 1, 25, 211, 34, 163, 96, 27, 134, 14, 32, 101, 146, 25, 139, 165, 45, 40, 164, 12, 134, 22, 104, 9, 160, 76, 13, 40, 168, 164, 32, 36, 101, 10, 4, 131, 89, 118, 95, 122, 237, 240, 222, 121, 251, 158, 179, 246, 218, 107, 255, 78, 242, 114, 31, 183, 103, 237, 181, 190, 223, 183, 30, 255, 220, 187, 207, 222, 251, 26, 241, 34, 64, 128, 0, 1, 2, 35, 4, 174, 49, 98, 140, 33, 4, 8, 16, 32, 64, 32, 2, 196, 38, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30, 32, 64, 128, 0, 129, 81, 2, 2, 100, 20, 155, 65, 4, 8, 16, 32, 32, 64, 236, 1, 2, 4, 8, 16, 24, 37, 32, 64, 70, 177, 25, 68, 128, 0, 1, 2, 2, 196, 30]
data = np.array(data).reshape(28,28,1)
At this point you should be able to use a tensorflow model on this, but if for some reason it does not accept the numpy array, you can try
data = tf.convert_to_tensor(data)
This will turn the numpy array into a tensorflow tensor. Hope that helps!
To create a COCO dataset of annotated images, you need to convert binary masks into either polygons or uncompressed run length encoding representations depending on the type of object.
The pycocotools library has functions to encode and decode into and from compressed RLE, but nothing for polygons and uncompressed RLE.
I can use skimage's measure library to generate polygons of masks, but I'm not sure how to create uncompressed RLEs.
I can use this RLE encoder to create a representation of RLE from an image, but I'm not sure what format COCO expects. COCO just mentions that they use a "custom Run Length Encoding (RLE) scheme"
for example,
ground_truth_binary_mask = np.array([[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[ 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[ 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[ 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=np.uint8)
fortran_ground_truth_binary_mask = np.asfortranarray(ground_truth_binary_mask)
rle(fortran_ground_truth_binary_mask)
outputs:
(array([26, 36, 46, 56, 61]), array([3, 3, 3, 3, 1]))
this is what a coco RLE looks like:
{
"segmentation": {
"counts": [
272,
2,
4,
4,
4,
4,
2,
9,
1,
2,
16,
43,
143,
24,
5,
8,
16,
44,
141,
25,
8,
5,
17,
44,
140,
26,
10,
2,
17,
45,
129,
4,
5,
27,
24,
5,
1,
45,
127,
38,
23,
52,
125,
40,
22,
53,
123,
43,
20,
54,
122,
46,
18,
54,
121,
54,
12,
53,
119,
57,
11,
53,
117,
59,
13,
51,
117,
59,
13,
51,
117,
60,
11,
52,
117,
60,
10,
52,
118,
60,
9,
53,
118,
61,
8,
52,
119,
62,
7,
52,
119,
64,
1,
2,
2,
51,
120,
120,
120,
101,
139,
98,
142,
96,
144,
93,
147,
90,
150,
87,
153,
85,
155,
82,
158,
76,
164,
66,
174,
61,
179,
57,
183,
54,
186,
52,
188,
49,
191,
47,
193,
21,
8,
16,
195,
20,
13,
8,
199,
18,
222,
17,
223,
16,
224,
16,
224,
15,
225,
15,
225,
15,
225,
15,
225,
15,
225,
15,
225,
15,
225,
15,
225,
15,
225,
14,
226,
14,
226,
14,
39,
1,
186,
14,
39,
3,
184,
14,
39,
4,
183,
13,
40,
6,
181,
14,
39,
7,
180,
14,
39,
9,
178,
14,
39,
10,
177,
14,
39,
11,
176,
14,
38,
14,
174,
14,
36,
19,
171,
15,
33,
32,
160,
16,
30,
35,
159,
18,
26,
38,
158,
19,
23,
41,
157,
20,
19,
45,
156,
21,
15,
48,
156,
22,
10,
53,
155,
23,
9,
54,
154,
23,
8,
55,
154,
24,
7,
56,
153,
24,
6,
57,
153,
25,
5,
57,
153,
25,
5,
58,
152,
25,
4,
59,
152,
26,
3,
59,
152,
26,
3,
59,
152,
27,
1,
60,
152,
27,
1,
60,
152,
86,
154,
80,
160,
79,
161,
42,
8,
29,
161,
41,
11,
22,
2,
3,
161,
40,
13,
18,
5,
3,
161,
40,
15,
2,
5,
8,
7,
2,
161,
40,
24,
6,
170,
35,
30,
4,
171,
34,
206,
34,
41,
1,
164,
34,
39,
3,
164,
34,
37,
5,
164,
34,
35,
10,
161,
36,
1,
3,
28,
17,
155,
41,
27,
16,
156,
41,
26,
17,
156,
41,
26,
16,
157,
27,
4,
10,
25,
16,
158,
27,
6,
8,
11,
2,
12,
6,
2,
7,
159,
27,
7,
14,
3,
4,
19,
6,
160,
26,
8,
22,
18,
5,
161,
26,
8,
22,
18,
4,
162,
26,
8,
23,
15,
4,
164,
23,
11,
23,
11,
7,
165,
19,
17,
22,
9,
6,
167,
19,
22,
18,
8,
3,
170,
18,
25,
16,
7,
1,
173,
17,
28,
15,
180,
17,
30,
12,
181,
16,
34,
6,
184,
15,
225,
14,
226,
13,
227,
12,
228,
11,
229,
10,
230,
9,
231,
9,
231,
9,
231,
9,
231,
8,
232,
8,
232,
8,
232,
8,
232,
8,
232,
8,
232,
7,
233,
7,
233,
7,
233,
7,
233,
8,
232,
8,
232,
8,
232,
9,
231,
9,
231,
9,
231,
10,
230,
10,
230,
11,
229,
13,
227,
14,
226,
16,
224,
17,
223,
19,
221,
23,
217,
31,
3,
5,
201,
39,
201,
39,
201,
39,
201,
39,
201,
39,
201,
40,
200,
40,
200,
41,
199,
41,
199,
41,
199,
22,
8,
12,
198,
22,
12,
8,
198,
22,
14,
6,
198,
22,
15,
6,
197,
22,
16,
5,
197,
22,
17,
5,
196,
22,
18,
4,
196,
22,
19,
4,
195,
22,
19,
5,
194,
22,
20,
4,
194,
25,
21,
1,
193,
27,
213,
29,
211,
30,
210,
35,
6,
6,
193,
49,
191,
50,
190,
50,
190,
51,
189,
51,
189,
52,
188,
53,
187,
53,
187,
54,
186,
54,
186,
54,
186,
55,
185,
55,
185,
55,
185,
55,
185,
55,
185,
55,
185,
55,
185,
55,
185,
55,
185,
55,
185,
55,
185,
55,
185,
55,
185,
55,
185,
55,
185,
28,
1,
26,
185,
23,
11,
21,
185,
20,
17,
17,
186,
18,
21,
15,
186,
16,
23,
14,
187,
14,
25,
14,
187,
14,
26,
12,
188,
14,
28,
10,
188,
14,
226,
14,
226,
16,
224,
17,
223,
19,
221,
20,
220,
22,
218,
24,
18,
3,
12,
3,
180,
25,
10,
1,
4,
6,
10,
6,
178,
28,
7,
12,
8,
8,
177,
49,
3,
12,
176,
65,
175,
67,
173,
69,
171,
53,
3,
14,
170,
37,
20,
9,
4,
1,
169,
36,
21,
8,
175,
35,
22,
7,
176,
34,
23,
7,
176,
34,
23,
6,
177,
35,
22,
6,
177,
35,
22,
8,
175,
35,
23,
9,
173,
35,
205,
36,
204,
39,
201,
43,
197,
48,
36,
1,
155,
48,
35,
3,
154,
49,
33,
5,
154,
48,
32,
6,
155,
49,
27,
10,
155,
51,
24,
11,
154,
54,
21,
11,
155,
56,
19,
11,
155,
56,
18,
11,
156,
56,
17,
11,
157,
56,
16,
12,
157,
56,
14,
13,
159,
56,
12,
13,
160,
61,
5,
14,
162,
78,
165,
75,
167,
73,
168,
72,
170,
70,
171,
69,
173,
67,
176,
64,
179,
61,
182,
58,
183,
57,
185,
54,
187,
53,
188,
51,
191,
49,
192,
47,
195,
45,
196,
43,
198,
42,
199,
40,
201,
38,
203,
36,
205,
34,
207,
32,
210,
28,
213,
26,
216,
22,
221,
16,
228,
8,
10250
],
"size": [
240,
320
]
}
}
Information on the format is available here: https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocotools/mask.py
RLE is a simple yet efficient format for storing binary masks. RLE
first divides a vector (or vectorized image) into a series of
piecewise constant regions and then for each piece simply stores the
length of that piece. For example, given M=[0 0 1 1 1 0 1] the RLE
counts would be [2 3 1 1], or for M=[1 1 1 1 1 1 0] the counts would
be [0 6 1] (note that the odd counts are always the numbers of zeros).
import numpy as np
from itertools import groupby
def binary_mask_to_rle(binary_mask):
rle = {'counts': [], 'size': list(binary_mask.shape)}
counts = rle.get('counts')
for i, (value, elements) in enumerate(groupby(binary_mask.ravel(order='F'))):
if i == 0 and value == 1:
counts.append(0)
counts.append(len(list(elements)))
return rle
test_list_1 = np.array([0, 0, 1, 1, 1, 0, 1])
test_list_2 = np.array([1, 1, 1, 1, 1, 1, 0])
print(binary_mask_to_rle(test_list_1))
print(binary_mask_to_rle(test_list_2))
output:
{'counts': [2, 3, 1, 1], 'size': [7]}
{'counts': [0, 6, 1], 'size': [7]}
You can use mask.frPyObjects(rle, size_x, size_y) to encode the RLE, and then do all the usual mask operations.
import json
import numpy as np
from pycocotools import mask
from skimage import measure
ground_truth_binary_mask = np.array([[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[ 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[ 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[ 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=np.uint8)
fortran_ground_truth_binary_mask = np.asfortranarray(ground_truth_binary_mask)
encode the mask to RLE:
rle = binary_mask_to_rle(fortran_ground_truth_binary_mask)
print(rle)
output:
{'counts': [6, 1, 40, 4, 5, 4, 5, 4, 21], 'size': [9, 10]}
compress the RLE, and then decode:
compressed_rle = mask.frPyObjects(rle, rle.get('size')[0], rle.get('size')[1])
mask.decode(compressed_rle)
output:
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=uint8)
As an improvement of #waspinator 's answer. This is 35% faster.
def binary_mask_to_rle(binary_mask):
rle = {'counts': [], 'size': list(binary_mask.shape)}
counts = rle.get('counts')
last_elem = 0
running_length = 0
for i, elem in enumerate(binary_mask.ravel(order='F')):
if elem == last_elem:
pass
else:
counts.append(running_length)
running_length = 0
last_elem = elem
running_length += 1
counts.append(running_length)
return rle
In order to decode the binary masks encoded in the COCO annotations, you need to first use the COCO's API to get the RLE and then use opencv to get the contours like this:
# Import libraries
import numpy as np
import cv2
import json
import mask
# Read the annotations
file_path = "coco/annotations/stuff_annotations_trainval2017/stuff_train2017.json"
with open(file_path, 'r') as f:
data = json.load(f)
updated_data = []
# For each annotation
for annotation in data['annotations']:
# Initialize variables
obj = {}
segmentation = []
segmentation_polygons = []
# Decode the binary mask
mask_list = mask.decode(annotation['segmentation'])
mask_list = np.ascontiguousarray(mask_list, dtype=np.uint8)
mask_new, contours, hierarchy = cv2.findContours((mask_list).astype(np.uint8), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# Get the contours
for contour in contours:
contour = contour.flatten().tolist()
segmentation.append(contour)
if len(contour) > 4:
segmentation.append(contour)
if len(segmentation) == 0:
continue
# Get the polygons as (x, y) coordinates
for i, segment in enumerate(segmentation):
poligon = []
poligons = []
for j in range(len(segment)):
poligon.append(segment[j])
if (j+1)%2 == 0:
poligons.append(poligon)
poligon = []
segmentation_polygons.append(poligons)
# Save the segmentation and polygons for the current annotation
obj['segmentation'] = segmentation
obj['segmentation_polygons'] = segmentation_polygons
updated_data.append(obj)
Note: Only the COCO stuff 2017 annotations are using binary masks, the COCO person 2017 annotations aren't, so you don't need to decode the latter and find their contours.
Inspired by this solution.
Do it like this:
import numpy as np
from pycocotools import mask as m
# Create bool array
n_a = np.random.normal(size=(10, 10))
b_a = np.array(n_a > 0.5, dtype=np.bool, order='F')
# Encode bool array
e_a = m.encode(b_a)
d_a = m.decode(e_a)
# Decode byte string rle encoded mask
sz = pred['mask']['size']
c = pred['mask']['counts'][2:-1]
es = str.encode(c)
t = {'size': [450, 800], 'counts': es}
dm = m.decode(t)