How to erode an image only using numpy? - python

I have the following M_Matrix
M = np.array([[0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1]])
which I want to erose using this structuring element.
st_element = np.ones((3, 3))
The final output sould seem like this
Output = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0],
[0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
My question is: is it possible to do erosion using only numpy_functions ?
thanks

Using sliding_window_view (not the fastest, but not the slowest either)
import numpy as np
from numpy.lib.stride_tricks import sliding_window_view
M = np.array([[0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1]]).astype(bool)
st_element = np.ones((3, 3), dtype=bool)
padded = np.pad(M, st_element.shape[0]//2)
windows = sliding_window_view(padded, window_shape=st_element.shape)
eroded = np.all(windows | ~st_element, axis=(-1, -2))
Checking that it gives the same as scipy:
from scipy.ndimage import binary_erosion
np.testing.assert_array_equal(eroded, binary_erosion(M, st_element))

Related

Python 2d array loop

It might be stupid question but I'm starting with python and I have no clue how to write it.
So I want to print this table in loop like on the screen and then I want it to be usable but It's hard for me to write it down (look on screen pls):
table = [print([random.randint(0,1) for x in range(10)]) for y in range(10)]
a = table
print(a)
console output
The values are printed using the print inside the list. But the method print return nothing, None, so you're saving 10 None in the outer list
table = [[random.randint(0, 1) for x in range(10)] for y in range(10)]
for row in table:
print(row)
a = table
print(a)
[1, 0, 0, 1, 1, 0, 1, 1, 1, 1]
[0, 1, 1, 0, 0, 1, 0, 1, 1, 0]
[1, 0, 1, 0, 0, 0, 0, 1, 1, 0]
[1, 1, 1, 1, 0, 1, 1, 1, 0, 0]
[0, 1, 0, 0, 1, 1, 0, 1, 0, 0]
[1, 0, 0, 0, 0, 1, 0, 0, 0, 1]
[0, 1, 0, 1, 1, 1, 0, 0, 0, 0]
[0, 1, 0, 1, 0, 1, 1, 1, 1, 1]
[1, 0, 0, 0, 1, 1, 1, 0, 1, 1]
[1, 1, 0, 0, 0, 0, 1, 1, 0, 0]
[[1, 0, 0, 1, 1, 0, 1, 1, 1, 1], [0, 1, 1, 0, 0, 1, 0, 1, 1, 0], [1, 0, 1, 0, 0, 0, 0, 1, 1, 0], [1, 1, 1, 1, 0, 1, 1, 1, 0, 0], [0, 1, 0, 0, 1, 1, 0, 1, 0, 0], [1, 0, 0, 0, 0, 1, 0, 0, 0, 1], [0, 1, 0, 1, 1, 1, 0, 0, 0, 0], [0, 1, 0, 1, 0, 1, 1, 1, 1, 1], [1, 0, 0, 0, 1, 1, 1, 0, 1, 1], [1, 1, 0, 0, 0, 0, 1, 1, 0, 0]]

Cplex Error: Adding trivial infeasible linear constraint

I want to solve an integer programming model with cplex python. I have this model:
a and h are matrixes with 0s and 1s. p is a set of numbers.
here is a part of my cplex code for this model:
p=[i for i in range (len(h))]
x=mdl.binary_var_dict(p,name='x')
#objective
mdl.minimize(0)
#constraints
#1
mdl.add_constraints(mdl.sum(h[i][k]*x[i] for i in p)==4 for k in T)
#2
mdl.add_constraints(mdl.sum(a[i][k]*x[i] for i in p)==4 for k in T)
mdl.print_information()
Solution = mdl.solve(log_output=False)
mdl.get_solve_status()
print(Solution)
When I run the program I get this error:
Error: Adding trivial infeasible linear constraint: 0 == 4, rank: 1
Error: Adding trivial infeasible linear constraint: 0 == 4, rank: 1
Error: Adding trivial infeasible linear constraint: 0 == 4, rank: 23
Error: Adding trivial infeasible linear constraint: 0 == 4, rank: 23
'h' is a 600*22 matrix and 'a' is reverse of h(if there's a 1 (or 0) in h, it is 0 (or 1) in a). A sample of h:
[1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0],
[1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0],
[1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0],
[1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0],
[1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0],
[1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0],
[1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0],
[1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0],
[1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0],
[1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0],
[1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0],
[1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0],
[1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0],
[1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0]]
I don't understand where is the problem.
The error messages tells you what happens: you added a constraint that is trivially infeasible, i.e., that can obviously not be satisfied. From the error message it seems you added some == 4 constraints with an empty left-hand side.
From your code it looks that this would happen if p is empty.

Turning a list into list of lists

I am writing a function which takes columns=c and rows=r (both can be unequal!) and that should a list of lists, where each row is a list containing c elements, all rows within a list. How do I create such sublists given the list below?
list = [0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1]
should return:
[[0, 0, 0, 0, 0], [1, 1, 0, 1, 1], [0, 0, 1, 1, 1], [1, 1, 1, 1, 0], [0, 1, 0, 1, 1]]
I tried to use split() however it seems like it works for strings only.
Numpy:
import numpy
c, r = 4, 5
list_ = [0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0]
numpy.array(list_).reshape(c, r).tolist()
#out (shortened example list to avoid 5x5):
[[0, 0, 0, 0, 0], [1, 1, 0, 1, 1], [0, 0, 1, 1, 1], [1, 1, 1, 1, 0]]
However, if your goal is to create "an cxr array with zeroes and ones", you should better use:
numpy.random.randint(0, high=2, size=(c, r))
# out
array([[1, 1, 1, 0, 0],
[1, 1, 0, 0, 0],
[0, 1, 1, 1, 0],
[1, 0, 0, 1, 0]])
Use itertools.islice: (Also don't use list as a variable name. It replaces the builtin function)
from itertools import islice
def chunker(data, rows, cols):
d = iter(data)
return [list(islice(d, cols)) for row in range(rows)]
data = [0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1]
result = chunker(data, 4, 5)
Result:
[[0, 0, 0, 0, 0],
[1, 1, 0, 1, 1],
[0, 0, 1, 1, 1],
[1, 1, 1, 1, 0]]
You can use a list comprehension:
c, r = 4, 5
list = [0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1]
list_of_lists = [list[i - c: i] for i in range(c, len(list), c)]
l= [0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1]
print([L[i:i+4] for i in range(0,len(L),4)])
output:
[[0, 0, 0, 0], [0, 1, 1, 0], [1, 1, 0, 0], [1, 1, 1, 1], [1, 1, 1, 0], [0, 1, 0, 1], [1]]
using slicing and list comprehension.
new_list=[list[i:i+5] for i in range(len(list)//5)]
just do this like it,it will be done.
a sample usage screenshot
Try this:
ls = [0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1]
[ls[i*5:i*5+5] for i in range(len(ls)//5)]
Out[1]:
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 1],
[0, 0, 0, 1, 1],
[0, 0, 1, 1, 0],
[0, 1, 1, 0, 1]]
Or as a function:
def split_list(list, length):
return [list[i*length:i*length+length] for i in range((len(list)//length))]
split_list(ls, 5)

Numpy multidimensional slice

If a have a 2d Numpy array:
array([[0, 1, 0, 0, 0, 1, 0, 0, 0, 1],
[0, 0, 0, 0, 1, 0, 1, 1, 1, 0],
[1, 0, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 1, 1, 1, 0, 1, 0, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 0, 1, 1]])
and I wanted to slice each row up to and including the first index position equal to 1, as below:
array([[0, 1],
[0, 0, 0, 0, 1],
[1],
[0, 0, 1,
[0, 0, 1])
Is it possible to achieve this using broadcasting, or must all output arrays have the same shape? I have a solution using the following, but I was curious if this could be achieved using broadcasting?
x = np.random.choice([0,1], size = [5,10])
idx = x.argmax(axis = 1)
np.array([row[:i] for row, i in zip(x, idx + 1)])
You can do this use dtype=object
a =np.array([[0, 1, 0, 0, 0, 1, 0, 0, 0, 1],
[0, 0, 0, 0, 1, 0, 1, 1, 1, 0],
[1, 0, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 1, 1, 1, 0, 1, 0, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 0, 1, 1]])
idx = a.argmax(axis = 1)
a = np.array([row[:i] for row, i in zip(a, idx + 1)], dtype=object)
The output is:
a = array([array([0, 1]), array([0, 0, 0, 0, 1]), array([1]),
array([0, 0, 1]), array([0, 0, 1])], dtype=object)

how do you add up the output of the first integers in every lists?

I have these five lists in which i want to get the values of each place added up. For example, if my list is:
[0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1]
[0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0]
[1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1]
[1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0]
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0]
I want the count of the first value be 2, the second 4, and so on and so on
Put them into a 2D list, transpose it with zip, map it to sum, and send it to list to evaluate that lazy object (list() call not needed in Python 2, as it returns a list already).
>>> l = [[0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1],
... [0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0],
... [1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1],
... [1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0],
... [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0]]
>>> list(map(sum, zip(*l)))
[2, 4, 5, 3, 3, 2, 1, 3, 4, 4, 3, 2, 2, 2, 2, 1, 3, 4, 2, 2]
Why don't you do something like this
a = [[0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1],
[0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1],
[1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0]]
list(map(sum, zip(*a)))

Categories

Resources