How to "extend" the array in Python? - python

I would like to extend the 2d array in python in some way.
No loops
F.e. if it is:
[[255, 255, 255],
[255, 255, 255],
[255, 255, 255]]
I would say I want to extend it by the factor of 2 and get like this:
[[255, 0, 255, 0, 255, 0],
[0, 0, 0, 0, 0, 0],
[255, 0, 255, 0, 255, 0],
[0, 0, 0, 0, 0, 0],
[255, 0, 255, 0, 255, 0],
[0, 0, 0, 0, 0, 0]]
and etc, if by 4 factor.
Is there any function?

Here is a solution using numpy. You didn't provide example for N=4, so I guessed :
import numpy as np
arr = np.array([[255, 255, 255], [255, 255, 255], [255, 255, 255]])
factor = 4
print(arr)
nx, ny = arr.shape
if nx != ny:
raise Exception("Array is not square")
step = 2 + factor//2 - 1
stop = nx * step
print('stop:', stop)
print('step:', step)
for x in range(1,stop,step):
print()
nx, ny = arr.shape
print('x:', x)
value = [[0]*nx]*(factor//2)
print('Inserting columns:', value)
arr = np.insert(arr, x, value, axis=1)
nx, ny = arr.shape
print(arr)
value = [[0]*ny]*(factor//2)
print('Inserting rows:', value)
arr = np.insert(arr, x, value, axis=0)
print(arr)
[[255 255 255]
[255 255 255]
[255 255 255]]
stop: 9
step: 3
x: 1
Inserting columns: [[0, 0, 0], [0, 0, 0]]
[[255 0 0 255 255]
[255 0 0 255 255]
[255 0 0 255 255]]
Inserting rows: [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
[[255 0 0 255 255]
[ 0 0 0 0 0]
[ 0 0 0 0 0]
[255 0 0 255 255]
[255 0 0 255 255]]
x: 4
Inserting columns: [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
[[255 0 0 255 0 0 255]
[ 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0]
[255 0 0 255 0 0 255]
[255 0 0 255 0 0 255]]
Inserting rows: [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0]]
[[255 0 0 255 0 0 255]
[ 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0]
[255 0 0 255 0 0 255]
[ 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0]
[255 0 0 255 0 0 255]]
x: 7
Inserting columns: [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0]]
[[255 0 0 255 0 0 255 0 0]
[ 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0]
[255 0 0 255 0 0 255 0 0]
[ 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0]
[255 0 0 255 0 0 255 0 0]]
Inserting rows: [[0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0]]
[[255 0 0 255 0 0 255 0 0]
[ 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0]
[255 0 0 255 0 0 255 0 0]
[ 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0]
[255 0 0 255 0 0 255 0 0]
[ 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0]]

You can create new bigger array with zeros
factor = 2
h, w = arr.shape[:2]
new_w = h*factor
new_h = h*factor
new_arr = np.zeros((new_h, new_w), np.uint8)
and then you can use for-loops with zip() and range(0, new_h, factor) to get value and its new position
for row, y in zip(arr, range(0, new_h, factor)):
for value, x in zip(row, range(0, new_w, factor)):
new_arr[y,x] = value
gives
[[255 0 255 0 255 0]
[ 0 0 0 0 0 0]
[255 0 255 0 255 0]
[ 0 0 0 0 0 0]
[255 0 255 0 255 0]
[ 0 0 0 0 0 0]]
If you use different value instead of 0 in range then you can get offset
offset_y = 1
offset_x = 1
for row, y in zip(arr, range(offset_y, new_h, factor)):
for value, x in zip(row, range(offset_x, new_w, factor)):
new_arr[y,x] = value
gives:
[[ 0 0 0 0 0 0]
[ 0 255 0 255 0 255]
[ 0 0 0 0 0 0]
[ 0 255 0 255 0 255]
[ 0 0 0 0 0 0]
[ 0 255 0 255 0 255]]
Working code
import numpy as np
arr = np.array([[255, 255, 255],
[255, 255, 255],
[255, 255, 255]]
)
factor = 2
h, w = arr.shape[:2]
new_w = h*factor
new_h = h*factor
new_arr = np.zeros((new_h, new_w), np.uint8)
offset_x = 0
offset_y = 0
for row, y in zip(arr, range(offset_y, new_h, factor)):
#print(row, y)
for value, x in zip(row, range(offset_x, new_w, factor)):
#print(y, x, value)
new_arr[y,x] = value
print(new_arr)
BTW: You could even use factor_x, factor_y with different values.
for example
factor_x = 4
factor_y = 2
in code
import numpy as np
arr = np.array([[255, 255, 255],
[255, 255, 255],
[255, 255, 255]]
)
factor_x = 4
factor_y = 2
h, w = arr.shape[:2]
new_w = h*factor_x
new_h = h*factor_y
new_arr = np.zeros((new_h, new_w), np.uint8)
offset_x = 0
offset_y = 0
for row, y in zip(arr, range(offset_y, new_h, factor_y)):
#print(row, y)
for value, x in zip(row, range(offset_x, new_w, factor_x)):
#print(y, x, value)
new_arr[y,x] = value
print(new_arr)
gives
[[255 0 0 0 255 0 0 0 255 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0 0 0]
[255 0 0 0 255 0 0 0 255 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0 0 0]
[255 0 0 0 255 0 0 0 255 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0 0 0]]

Extending is simple with slicing:
array = np.array([[255, 255, 255], [255, 255, 255], [255, 255, 255]])
factor = 2
extended_array = np.zeros((array.shape[0]*factor, array.shape[1]*factor))
extended_array[::factor,::factor] = array

You can do this without numpy just with list comprehension:
lst = [[255, 255, 255],
[255, 255, 255],
[255, 255, 255]]
extend_list = [ [lst[j // 2][i // 2] if j % 2 == 0 and i % 2 == 0 else 0 for i in range( 2 * (len(lst[j // 2])) )] if j != len(2 * lst) else [0 for _ in range( (2 * len(lst)) -1)] for j in range(2 * (len(lst)) )]
print(extend_list)
the output:
[[255, 0, 255, 0, 255, 0], [0, 0, 0, 0, 0, 0], [255, 0, 255, 0, 255, 0], [0, 0, 0], [255, 0, 255, 0, 255, 0], [0, 0, 0, 0, 0, 0]]

Related

Finding perimeter coordinates of a mask

[[ 0, 0, 0, 0, 255, 0, 0, 0, 0],
[ 0, 0, 255, 255, 255, 255, 255, 0, 0],
[ 0, 255, 255, 255, 255, 255, 255, 255, 0],
[ 0, 255, 255, 255, 255, 255, 255, 255, 0],
[255, 255, 255, 255, 255, 255, 255, 255, 255],
[ 0, 255, 255, 255, 255, 255, 255, 255, 0],
[ 0, 255, 255, 255, 255, 255, 255, 255, 0],
[ 0, 0, 255, 255, 255, 255, 255, 0, 0],
[ 0, 0, 0, 0, 255, 0, 0, 0, 0]]
I have a mask array like the one above. I would like to get the x and y coordinates belonging to the perimeter of the mask. The perimeter points are the ones shown in the array below:
[[ 0, 0, 0, 0, 255, 0, 0, 0, 0],
[ 0, 0, 255, 255, 0, 255, 255, 0, 0],
[ 0, 255, 0, 0, 0, 0, 0, 255, 0],
[ 0, 255, 0, 0, 0, 0, 0, 255, 0],
[255, 0, 0, 0, 0, 0, 0, 0, 255],
[ 0, 255, 0, 0, 0, 0, 0, 255, 0],
[ 0, 255, 0, 0, 0, 0, 0, 255, 0],
[ 0, 0, 255, 255, 0, 255, 255, 0, 0],
[ 0, 0, 0, 0, 255, 0, 0, 0, 0]]
In the array above, I could just use numpy.nonzero() but I was unable to apply this logic to the original array because it returns a tuple of arrays each containing all the x or y values of all non zero elements without partitioning by row.
I wrote the code below which works but seems inefficient:
height = mask.shape[0]
width = mask.shape[1]
y_coords = []
x_coords = []
for y in range(1,height-1,1):
for x in range(0,width-1,1):
val = mask[y,x]
prev_val = mask[y,(x-1)]
next_val = mask[y, (x+1)]
top_val = mask[y-1, x]
bot_val = mask[y+1, x]
if (val != 0 and prev_val == 0) or (val != 0 and next_val == 0) or (val != 0 and top_val == 0) or (val != 0 and bot_val == 0):
y_coords.append(y)
x_coords.append(x)
I am new to python and would like to learn a better way to do this. Perhaps using Numpy?
I played a bit with your problem and found a solution and I realized you could use convolutions to count the number of neighboring 255s for each cell, and then perform a filtering of points based on the appropriate values of neighbors.
I am giving a detailed explanation below, although one part was trial and error and you could potentially skip it and get directly to the code if you understand that convolutions can count neighbors in binary images.
First observation: When does a point belong to the perimeter of the mask?
Well, that point has to have a value of 255 and "around" it, there must be at least one (and possibly more) 0.
Next: What is the definition of "around"?
We could consider all four cardinal (i.e. North, East, South, West) neighbors. In this case, a point of the perimeter must have at least one cardinal neighbor which is 0.
You have already done that, and truly, I cannot thing of a faster way by this definition.
What if we extended the definition of "around"?
Now, let's consider the neighbors of a point at (i,j) all points along an N x N square centered on (i,j). I.e. all points (x,y) such that i-N/2 <= x <= i+N/2 and j-N/2 <= y <= j+N/2 (where N is odd and ignoring out of bounds for the moment).
This is more useful from a performance point of view, because the operation of sliding "windows" along the points of 2D arrays is called a "convolution" operation. There are built in functions to perform such operations on numpy arrays really fast. The scipy.ndimage.convolve works great.
I won't attempt to fully explain convolutions here (the internet is ful of nice visuals), but the main idea is that the convolution essentially replaces the value of each cell with the weighted sum of the values of all its neighboring cells. Depending on what weight matrix, (or kernel) you specify, the convolution does different things.
Now, if your mask was 1s and 0s, to count the number of neighboring ones around a cell, you would need a kernel matrix of 1s everywhere (since the weighted sum will simply add the original ones of your mask and cancel the 0s). So we will scale the values from [0, 255] to [0,1].
Great, we know how to quickly count the neighbors of a point within an area, but the two questions are
What area size should we choose?
How many neighbors do the points in the perimeter have, now that we are including diagonal and more faraway neighbors?
I suppose there is an explicit answer to that, but I did some trial and error. It turns out, we need N=5, at which case the number of neighbors being one for each point in the original mask is the following:
[[ 3 5 8 10 11 10 8 5 3]
[ 5 8 12 15 16 15 12 8 5]
[ 8 12 17 20 21 20 17 12 8]
[10 15 20 24 25 24 20 15 10]
[11 16 21 25 25 25 21 16 11]
[10 15 20 24 25 24 20 15 10]
[ 8 12 17 20 21 20 17 12 8]
[ 5 8 12 15 16 15 12 8 5]
[ 3 5 8 10 11 10 8 5 3]]
Comparing that matrix with your original mask, the points on the perimeter are the ones having values between 11 and 15 (inclusive) [1]. So we simply filter out the rest using np.where().
A final caveat: We need to explicilty say to the convolve function how to treat points near the edges, where an N x N window won't fit. In those cases, we tell it to treat out of bounds values as 0s.
The full code is following:
from scipy import ndimage as ndi
mask //= 255
kernel = np.ones((5,5))
C = ndi.convolve(mask, kernel, mode='constant', cval=0)
#print(C) # The C matrix contains the number of neighbors for each cell.
outer = np.where( (C>=11) & (C<=15 ), 255, 0)
print(outer)
[[ 0 0 0 0 255 0 0 0 0]
[ 0 0 255 255 0 255 255 0 0]
[ 0 255 0 0 0 0 0 255 0]
[ 0 255 0 0 0 0 0 255 0]
[255 0 0 0 0 0 0 0 255]
[ 0 255 0 0 0 0 0 255 0]
[ 0 255 0 0 0 0 0 255 0]
[ 0 0 255 255 0 255 255 0 0]
[ 0 0 0 0 255 0 0 0 0]]
[1] Note that we are also counting the point itself as one of its own neighbors. That's alright.
I think this would work, I edit my answer based on my new understanding of the problem you want the outer pixel of 255 circle
What I did here is getting all the axis of where pixels are 255 items (print it to see) and then selecting the first occurrence and last occurrence that's it easy
result=np.where(pixel==255)
items=list(zip(result[0],result[1]))
unique=[]
perimiter=[]
for index in range(len(items)-1):
if items[index][0]!=items[index+1][0] or items[index][0] not in unique:
unique.append(items[index][0])
perimiter.append(items[index])
perimiter.append(items[-1])
Output
[(0, 4),
(1, 2),
(1, 6),
(2, 1),
(2, 7),
(3, 1),
(3, 7),
(4, 0),
(4, 8),
(5, 1),
(5, 7),
(6, 1),
(6, 7),
(7, 2),
(7, 6),
(8, 4)]

How to create a discrete RGB colourmap with N colours using numpy

I am trying to create a really simple colourmap using RGB triples. That has a discrete number of colours.
Here is the shape that I am trying to make it follow:
I know it is probably not a true RGB spectrum, but i wanted it to be as easy to compute as possible.
I want to be able to generate an array of N 8-bit RGB tuples that are evenly spaced along the line.
For easy instances where all of the points in the image above fall on colours, it is easy to generate using numpy.linspace() using the following code:
import numpy as np
# number of discrete colours
N = 9
# generate R array
R = np.zeros(N).astype(np.uint8)
R[:int(N/4)] = 255
R[int(N/4):int(2*N/4)+1] = np.linspace(255,0,num=(N/4)+1,endpoint=True)
# generate G array
G = 255*np.ones(N).astype(np.uint8)
G[0:int(N/4)+1] = np.linspace(0,255,num=(N/4)+1,endpoint=True)
G[int(3*N/4):] = np.linspace(255,0,num=(N/4)+1,endpoint=True)
# generate B array
B = np.zeros(N).astype(np.uint8)
B[int(2*N/4):int(3*N/4)+1] = np.linspace(0,255,num=(N/4)+1,endpoint=True)
B[int(3*N/4)+1:] = 255
# stack arrays
RGB = np.dstack((R,G,B))[0]
This code works fine for 5 colours:
r 255 255 0 0 0
g 0 255 255 255 0
b 0 0 0 255 255
9 colours:
r 255 255 255 127 0 0 0 0 0
g 0 127 255 255 255 255 255 127 0
b 0 0 0 0 0 127 255 255 255
13 colours:
r 255 255 255 255 170 85 0 0 0 0 0 0 0
g 0 85 170 255 255 255 255 255 255 255 170 85 0
b 0 0 0 0 0 0 0 85 170 255 255 255 255
etc.. but I'm having trouble working out how to make it work for an arbitrary N number of colours because the linspace trick only works if it is going from one endpoint to another.
Can someone please help me with working out how to do it? Any ideas for how to make my code above more efficient would be great as well, I am just learning how to use numpy after putting it off for ages..
Here is one reasonably convenient method using np.clip:
def spec(N):
t = np.linspace(-510, 510, N)
return np.round(np.clip(np.stack([-t, 510-np.abs(t), t], axis=1), 0, 255)).astype(np.uint8)
It avoids the problem you describe by only relying on the only two points that are guaranteed to be on the grid for any N which are the first and last points.
Examples:
>>> spec(5)
array([[255, 0, 0],
[255, 255, 0],
[ 0, 255, 0],
[ 0, 255, 255],
[ 0, 0, 255]], dtype=uint8)
>>> spec(10)
array([[255, 0, 0],
[255, 113, 0],
[255, 227, 0],
[170, 255, 0],
[ 57, 255, 0],
[ 0, 255, 57],
[ 0, 255, 170],
[ 0, 227, 255],
[ 0, 113, 255],
[ 0, 0, 255]], dtype=uint8)
If you just want RGB at given levels, the diagram that you have posted itself serves as the answer -
R = [255] * 256
R.extend(list(reversed(range(256))))
R.extend([0] * 256)
R.extend([0] * 256)
G = list(range(256))
G.extend([255] * 256)
G.extend([255] * 256)
G.extend(list(reversed(range(256))))
B = [0] * 256
B.extend([0] * 256)
B.extend(list(range(256)))
B.extend([255] * 256)
level = 5
step = 1024 // (level -1)
print(R[::step])
print(G[::step])
print(B[::step])

Obtaining pixel values within CV2 contours

I'm trying to get pixel values within contours. I've followed along with answers to similar questions but my results are off.
This block of code finds contours for an image and then iterates through them to find the contour containing the largest area. I added the ending if statement that tries to get the RGB value of the code if it is during daylight hours. The original image (video frame) is passed to a function I wrote (grab_rgb), along with the contour.
thresh = cv2.dilate(thresh, None, iterations=2)
(_, cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# look for motion
motion_found = False
biggest_area = 0
# examine the contours, looking for the largest one
for c in cnts:
(x, y, w, h) = cv2.boundingRect(c)
# get an approximate area of the contour
found_area = w * h
# find the largest bounding rectangle
if (found_area > MIN_AREA) and (found_area > biggest_area):
biggest_area = found_area
motion_found = True
if not is_nighttime():
rgb = grab_rgb(image, c)
else:
rgb = 'nighttime'
This is the function I wrote:
def grab_rgb(image, c):
pixels = []
# TODO: Convert to real code
# Detect pixel values (RGB)
mask = np.zeros_like(image)
cv2.drawContours(mask, c, -1, color=255, thickness=-1)
points = np.where(mask == 255)
for point in points:
pixel = (image[point[1], point[0]])
pixel = pixel.tolist()
pixels.append(pixel)
pixels = [tuple(l) for l in pixels]
car_color = (pixels[1])
r = car_color[0]
g = car_color[1]
b = car_color[2]
pixel_string = '{0},{1},{2}'.format(r, g, b)
return pixel_string
The code runs, but returns only three RGB values, with only the second value containing anything meaningful (values 0 and 2 are [0,0,0],[0,0,0]. There should definitely be more than three pixels within the contours, so I'm not sure where I went wrong.
EDIT: I realized it might be helpful to include what is actually being stored in the variables.
mask:
[[[ 0 0 0]
[ 0 0 0]
[ 0 0 0]
...,
[ 0 0 0]
[ 0 0 0]
[ 0 0 0]]
[[ 0 0 0]
[255 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]
[ 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 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]]]
points:
(array([ 1, 1, 3, 5, 10, 11, 11, 12, 12, 13, 13, 14, 14], dtype=int32), array([ 1, 22, 22, 24, 24, 21, 23, 16, 20, 9, 15, 1, 8], dtype=int32), array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int32))
pixel:
[0, 0, 0] [136, 89, 96] [0, 0, 0]
pixels:
[(0, 0, 0), (136, 89, 96), (0, 0, 0)]
car_color:
(136, 89, 96)
It seems like what you've asked the code to return is the RGB value of just the second point in the pixel values list (called 'pixels' here ) of the points in every contour passed to grab_rgb, with
car_color = (pixels[1])
r = car_color[0]
g = car_color[1]
b = car_color[2]
So the output should mean that your image has atleast three detected contours satisfying your area constraints, and that the RGB values of the second point in the contours' point lists are what you mentioned([0,0,0],[x,y,z] and [0,0,0]).

Python sage: How do I computer a nullspace (kernel) for a stoichiometric matrix?

In a desperate attempt to switch from Matlab to python, I am encountering the following problem:
In Matlab, I am able to define a matrix like:
N = [1 0 0 0 -1 -1 -1 0 0 0;% A
0 1 0 0 1 0 0 -1 -1 0;% B
0 0 0 0 0 1 0 1 0 -1;% C
0 0 0 0 0 0 1 0 0 -1;% D
0 0 0 -1 0 0 0 0 0 1;% E
0 0 -1 0 0 0 0 0 1 1]% F
The rational basis nullspace (kernel) can then be calculated by:
K_nur= null(N,'r')
And the orthonormal basis like:
K_nuo= null(N)
This outputs the following:
N =
1 0 0 0 -1 -1 -1 0 0 0
0 1 0 0 1 0 0 -1 -1 0
0 0 0 0 0 1 0 1 0 -1
0 0 0 0 0 0 1 0 0 -1
0 0 0 -1 0 0 0 0 0 1
0 0 -1 0 0 0 0 0 1 1
K_nur =
1 -1 0 2
-1 1 1 0
0 0 1 1
0 0 0 1
1 0 0 0
0 -1 0 1
0 0 0 1
0 1 0 0
0 0 1 0
0 0 0 1
K_nuo =
0.5933 0.1332 0.3070 -0.3218
-0.0930 0.0433 0.2029 0.7120
0.1415 0.0084 0.5719 0.2220
0.3589 0.1682 -0.0620 0.1682
-0.1628 0.4518 0.3389 -0.4617
0.3972 -0.4867 0.0301 -0.0283
0.3589 0.1682 -0.0620 0.1682
-0.0383 0.6549 -0.0921 0.1965
-0.2174 -0.1598 0.6339 0.0538
0.3589 0.1682 -0.0620 0.1682
I have been trying to replicate this in Python SAGE, but so far, I have had no success. My code looks like this:
st1= matrix([
[ 1, 0, 0, 0,-1,-1,-1, 0, 0, 0],
[ 0, 1, 0, 0, 1, 0, 0,-1,-1, 0],
[ 0, 0, 0, 0, 0, 1, 0, 1, 0,-1],
[ 0, 0, 0, 0, 0, 0, 1, 0, 0,-1],
[ 0, 0, 0,-1, 0, 0, 0, 0, 0, 1],
[ 0, 0,-1, 0, 0, 0, 0, 0, 1, 1]])
print st1
null2_or= transpose(st1).kernel()
null2_ra= transpose(st1).kernel().basis()
print "nullr2_or"
print null2_or
print "nullr2_ra"
print null2_ra
Note: The transpose was introduced after reading through some tutorials on this and has to do with the nature of SAGE automatically computing the kernel from the left (which in this case yields no result at all).
The problem with this now is: It DOES print me something... But not the right thing.
The output is as follows:
sage: load stochiometric.py
[ 1 0 0 0 -1 -1 -1 0 0 0]
[ 0 1 0 0 1 0 0 -1 -1 0]
[ 0 0 0 0 0 1 0 1 0 -1]
[ 0 0 0 0 0 0 1 0 0 -1]
[ 0 0 0 -1 0 0 0 0 0 1]
[ 0 0 -1 0 0 0 0 0 1 1]
nullr2_or
Free module of degree 10 and rank 4 over Integer Ring
Echelon basis matrix:
[ 1 0 0 1 0 0 1 1 -1 1]
[ 0 1 0 1 0 -1 1 2 -1 1]
[ 0 0 1 -1 0 1 -1 -2 2 -1]
[ 0 0 0 0 1 -1 0 1 0 0]
nullr2_ra
[
(1, 0, 0, 1, 0, 0, 1, 1, -1, 1),
(0, 1, 0, 1, 0, -1, 1, 2, -1, 1),
(0, 0, 1, -1, 0, 1, -1, -2, 2, -1),
(0, 0, 0, 0, 1, -1, 0, 1, 0, 0)
]
Upon closer inspection, you can see that the resulting kernel matrix (nullspace) looks similar, but is not the same.
Does anyone know what I need to do to get the same result as in Matlab and, if possible, how to obtain the orthonormal result (in Matlab called K_nuo).
I have tried to look through the tutorials, documentation etc., but so far, no luck.
There might be a way do this with SAGE builtin functions; I'm not sure.
However, if a numpy/python-based solution will do, then:
import numpy as np
def null(A, eps=1e-15):
"""
http://mail.scipy.org/pipermail/scipy-user/2005-June/004650.html
"""
u, s, vh = np.linalg.svd(A)
n = A.shape[1] # the number of columns of A
if len(s)<n:
expanded_s = np.zeros(n, dtype = s.dtype)
expanded_s[:len(s)] = s
s = expanded_s
null_mask = (s <= eps)
null_space = np.compress(null_mask, vh, axis=0)
return np.transpose(null_space)
st1 = np.matrix([
[ 1, 0, 0, 0,-1,-1,-1, 0, 0, 0],
[ 0, 1, 0, 0, 1, 0, 0,-1,-1, 0],
[ 0, 0, 0, 0, 0, 1, 0, 1, 0,-1],
[ 0, 0, 0, 0, 0, 0, 1, 0, 0,-1],
[ 0, 0, 0,-1, 0, 0, 0, 0, 0, 1],
[ 0, 0,-1, 0, 0, 0, 0, 0, 1, 1]])
K = null(st1)
print(K)
yields the orthonormal null space:
[[ 0.59330559 0.13320203 0.30701044 -0.32180406]
[-0.09297005 0.04333798 0.20286425 0.71195719]
[ 0.14147329 0.00837169 0.5718718 0.22197807]
[ 0.35886225 0.16816832 -0.06199711 0.16817506]
[-0.16275558 0.45177747 0.33887617 -0.46165922]
[ 0.39719892 -0.48674377 0.03013138 -0.0283199 ]
[ 0.35886225 0.16816832 -0.06199711 0.16817506]
[-0.03833668 0.65491209 -0.09212849 0.19649496]
[-0.21738895 -0.15979664 0.63386891 0.05380301]
[ 0.35886225 0.16816832 -0.06199711 0.16817506]]
this confirms the columns have the null space property:
print(np.allclose(st1*K, 0))
# True
and this confirms that K is orthonormal:
print(np.allclose(K.T*K, np.eye(4)))
# True
Something like this should work:
sage: st1= matrix([
[ 1, 0, 0, 0,-1,-1,-1, 0, 0, 0],
[ 0, 1, 0, 0, 1, 0, 0,-1,-1, 0],
[ 0, 0, 0, 0, 0, 1, 0, 1, 0,-1],
[ 0, 0, 0, 0, 0, 0, 1, 0, 0,-1],
[ 0, 0, 0,-1, 0, 0, 0, 0, 0, 1],
[ 0, 0,-1, 0, 0, 0, 0, 0, 1, 1]])
sage: K = st1.right_kernel(); K
Free module of degree 10 and rank 4 over Integer Ring
Echelon basis matrix:
[ 1 0 0 1 0 0 1 1 -1 1]
[ 0 1 0 1 0 -1 1 2 -1 1]
[ 0 0 1 -1 0 1 -1 -2 2 -1]
[ 0 0 0 0 1 -1 0 1 0 0]
sage: M = K.basis_matrix()
The gram_schmidt method gives a pair of matrices. Type M.gram_schmidt? to see the documentation.
sage: M.gram_schmidt() # rows are orthogonal, not orthonormal
(
[ 1 0 0 1 0 0 1 1 -1 1]
[ -1 1 0 0 0 -1 0 1 0 0]
[ 5/12 3/4 1 1/6 0 1/4 1/6 -1/12 5/6 1/6]
[ 12/31 -25/62 4/31 -9/62 1 -29/62 -9/62 10/31 17/62 -9/62],
[ 1 0 0 0]
[ 1 1 0 0]
[ -7/6 -3/4 1 0]
[ 1/6 1/2 -4/31 1]
)
sage: M.gram_schmidt()[0] # rows are orthogonal, not orthonormal
[ 1 0 0 1 0 0 1 1 -1 1]
[ -1 1 0 0 0 -1 0 1 0 0]
[ 5/12 3/4 1 1/6 0 1/4 1/6 -1/12 5/6 1/6]
[ 12/31 -25/62 4/31 -9/62 1 -29/62 -9/62 10/31 17/62 -9/62]
sage: M.change_ring(RDF).gram_schmidt()[0] # orthonormal
[ 0.408248290464 0.0 0.0 0.408248290464 0.0 0.0 0.408248290464 0.408248290464 -0.408248290464 0.408248290464]
[ -0.5 0.5 0.0 0.0 0.0 -0.5 0.0 0.5 0.0 0.0]
[ 0.259237923683 0.466628262629 0.622171016838 0.103695169473 0.0 0.15554275421 0.103695169473 -0.0518475847365 0.518475847365 0.103695169473]
[ 0.289303646409 -0.30135796501 0.0964345488031 -0.108488867403 0.747367753224 -0.349575239411 -0.108488867403 0.241086372008 0.204923416206 -0.108488867403]
The matrix st1 has integer entries, so Sage treats it as a matrix of integers, and tries to do as much as possible with integer arithmetic, and failing that, rational arithmetic. Because of this, Gram-Schmidt orthonormalization will fail, since it involves taking square roots. This is why the method change_ring(RDF) is there: RDF stands for Real Double Field. You could instead just change one entry of st1 from 1 to 1.0, and then it will treat st1 as a matrix over RDF from the start and you won't need to do this change_ring anywhere.
To expand on John's great answer, I think you just have two different bases for the same vector space. Note his use of right_kernel.
sage: st1= matrix([
....: [ 1, 0, 0, 0,-1,-1,-1, 0, 0, 0],
....: [ 0, 1, 0, 0, 1, 0, 0,-1,-1, 0],
....: [ 0, 0, 0, 0, 0, 1, 0, 1, 0,-1],
....: [ 0, 0, 0, 0, 0, 0, 1, 0, 0,-1],
....: [ 0, 0, 0,-1, 0, 0, 0, 0, 0, 1],
....: [ 0, 0,-1, 0, 0, 0, 0, 0, 1, 1]])
sage: st2 = matrix([[1,-1, 0, 2],
....: [-1, 1, 1, 0],
....: [ 0, 0, 1, 1],
....: [ 0, 0, 0, 1],
....: [ 1, 0, 0, 0],
....: [ 0,-1, 0, 1],
....: [ 0, 0, 0, 1],
....: [ 0, 1, 0, 0],
....: [ 0, 0, 1, 0],
....: [ 0, 0, 0, 1]])
sage: st2 = st2.transpose()
sage: st2
[ 1 -1 0 0 1 0 0 0 0 0]
[-1 1 0 0 0 -1 0 1 0 0]
[ 0 1 1 0 0 0 0 0 1 0]
[ 2 0 1 1 0 1 1 0 0 1]
sage: st1.right_kernel()
Free module of degree 10 and rank 4 over Integer Ring
Echelon basis matrix:
[ 1 0 0 1 0 0 1 1 -1 1]
[ 0 1 0 1 0 -1 1 2 -1 1]
[ 0 0 1 -1 0 1 -1 -2 2 -1]
[ 0 0 0 0 1 -1 0 1 0 0]
sage: st2.row_space()
Free module of degree 10 and rank 4 over Integer Ring
Echelon basis matrix:
[ 1 0 0 1 0 0 1 1 -1 1]
[ 0 1 0 1 0 -1 1 2 -1 1]
[ 0 0 1 -1 0 1 -1 -2 2 -1]
[ 0 0 0 0 1 -1 0 1 0 0]
Your spaces are the same, just different bases in Sage and Matlab.

How to make a checkerboard in numpy?

I'm using numpy to initialize a pixel array to a gray checkerboard (the classic representation for "no pixels", or transparent). It seems like there ought to be a whizzy way to do it with numpy's amazing array assignment/slicing/dicing operations, but this is the best I've come up with:
w, h = 600, 800
sq = 15 # width of each checker-square
self.pix = numpy.zeros((w, h, 3), dtype=numpy.uint8)
# Make a checkerboard
row = [[(0x99,0x99,0x99),(0xAA,0xAA,0xAA)][(i//sq)%2] for i in range(w)]
self.pix[[i for i in range(h) if (i//sq)%2 == 0]] = row
row = [[(0xAA,0xAA,0xAA),(0x99,0x99,0x99)][(i//sq)%2] for i in range(w)]
self.pix[[i for i in range(h) if (i//sq)%2 == 1]] = row
It works, but I was hoping for something simpler.
def checkerboard(shape):
return np.indices(shape).sum(axis=0) % 2
Most compact, probably the fastest, and also the only solution posted that generalizes to n-dimensions.
I'd use the Kronecker product kron:
np.kron([[1, 0] * 4, [0, 1] * 4] * 4, np.ones((10, 10)))
The checkerboard in this example has 2*4=8 fields of size 10x10 in each direction.
this ought to do it
any size checkerboard you want (just pass in width and height, as w, h); also i have hard-coded cell height/width to 1, though of course this could also be parameterized so that an arbitrary value is passed in:
>>> import numpy as NP
>>> def build_checkerboard(w, h) :
re = NP.r_[ w*[0,1] ] # even-numbered rows
ro = NP.r_[ w*[1,0] ] # odd-numbered rows
return NP.row_stack(h*(re, ro))
>>> checkerboard = build_checkerboard(5, 5)
>>> checkerboard
Out[3]: array([[0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
[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],
[0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
[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],
[0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
[1, 0, 1, 0, 1, 0, 1, 0, 1, 0]])
with this 2D array, it's simple to render an image of a checkerboard, like so:
>>> import matplotlib.pyplot as PLT
>>> fig, ax = PLT.subplots()
>>> ax.imshow(checkerboard, cmap=PLT.cm.gray, interpolation='nearest')
>>> PLT.show()
Here's another way to do it using ogrid which is a bit faster:
import numpy as np
import Image
w, h = 600, 800
sq = 15
color1 = (0xFF, 0x80, 0x00)
color2 = (0x80, 0xFF, 0x00)
def use_ogrid():
coords = np.ogrid[0:w, 0:h]
idx = (coords[0] // sq + coords[1] // sq) % 2
vals = np.array([color1, color2], dtype=np.uint8)
img = vals[idx]
return img
def use_fromfunction():
img = np.zeros((w, h, 3), dtype=np.uint8)
c = np.fromfunction(lambda x, y: ((x // sq) + (y // sq)) % 2, (w, h))
img[c == 0] = color1
img[c == 1] = color2
return img
if __name__ == '__main__':
for f in (use_ogrid, use_fromfunction):
img = f()
pilImage = Image.fromarray(img, 'RGB')
pilImage.save('{0}.png'.format(f.func_name))
Here are the timeit results:
% python -mtimeit -s"import test" "test.use_fromfunction()"
10 loops, best of 3: 307 msec per loop
% python -mtimeit -s"import test" "test.use_ogrid()"
10 loops, best of 3: 129 msec per loop
You can use Numpy's tile function to get checkerboard array of size n*m where n and m should be even numbers for the right result...
def CreateCheckboard(n,m):
list_0_1 = np.array([ [ 0, 1], [ 1, 0] ])
checkerboard = np.tile(list_0_1, ( n//2, m//2))
print(checkerboard.shape)
return checkerboard
CreateCheckboard(4,6)
which gives the output:
(4, 6)
array([[0, 1, 0, 1, 0, 1],
[1, 0, 1, 0, 1, 0],
[0, 1, 0, 1, 0, 1],
[1, 0, 1, 0, 1, 0]])
You can use the step of start:stop:step for slicing method to update a matrix horizontally and vertically:
Here x[1::2, ::2] picks every other element starting from the first element on the row and for every second row of the matrix.
import numpy as np
print("Checkerboard pattern:")
x = np.zeros((8,8),dtype=int)
# (odd_rows, even_columns)
x[1::2,::2] = 1
# (even_rows, odd_columns)
x[::2,1::2] = 1
print(x)
Late, but for posterity:
def check(w, h, c0, c1, blocksize):
tile = np.array([[c0,c1],[c1,c0]]).repeat(blocksize, axis=0).repeat(blocksize, axis=1)
grid = np.tile(tile, ( h/(2*blocksize)+1, w/(2*blocksize)+1, 1))
return grid[:h,:w]
I'm not sure if this is better than what I had:
c = numpy.fromfunction(lambda x,y: ((x//sq) + (y//sq)) % 2, (w,h))
self.chex = numpy.array((w,h,3))
self.chex[c == 0] = (0xAA, 0xAA, 0xAA)
self.chex[c == 1] = (0x99, 0x99, 0x99)
A perfplot analysis shows that the best (fastest, most readable, memory-efficient) solution is via slicing,
def slicing(n):
A = np.zeros((n, n), dtype=int)
A[1::2, ::2] = 1
A[::2, 1::2] = 1
return A
The stacking solution is a bit faster large matrices, but arguably less well readable. The top-voted answer is also the slowest.
Code to reproduce the plot:
import numpy as np
import perfplot
def indices(n):
return np.indices((n, n)).sum(axis=0) % 2
def slicing(n):
A = np.zeros((n, n), dtype=int)
A[1::2, ::2] = 1
A[::2, 1::2] = 1
return A
def tile(n):
return np.tile([[0, 1], [1, 0]], (n // 2, n // 2))
def stacking(n):
row0 = np.array(n // 2 * [0, 1] + (n % 2) * [0])
row1 = row0 ^ 1
return np.array(n // 2 * [row0, row1] + (n % 2) * [row0])
def ogrid(n):
coords = np.ogrid[0:n, 0:n]
return (coords[0] + coords[1]) % 2
b = perfplot.bench(
setup=lambda n: n,
kernels=[slicing, indices, tile, stacking, ogrid],
n_range=[2 ** k for k in range(14)],
xlabel="n",
)
b.save("out.png")
b.show()
Can't you use hstack and vstack? See here.
Like this:
>>> import numpy as np
>>> b = np.array([0]*4)
>>> b.shape = (2,2)
>>> w = b + 0xAA
>>> r1 = np.hstack((b,w,b,w,b,w,b))
>>> r2 = np.hstack((w,b,w,b,w,b,w))
>>> board = np.vstack((r1,r2,r1,r2,r1,r2,r1))
import numpy as np
a=np.array(([1,0]*4+[0,1]*4)*4).reshape((8,8))
print(a)
[[1 0 1 0 1 0 1 0]
[0 1 0 1 0 1 0 1]
[1 0 1 0 1 0 1 0]
[0 1 0 1 0 1 0 1]
[1 0 1 0 1 0 1 0]
[0 1 0 1 0 1 0 1]
[1 0 1 0 1 0 1 0]
[0 1 0 1 0 1 0 1]]
For those wanting arbitrarily sized squares/rectangles:
import numpy as np
# if you want X squares per axis, do squaresize=[i//X for i in boardsize]
def checkerboard(boardsize, squaresize):
return np.fromfunction(lambda i, j: (i//squaresize[0])%2 != (j//squaresize[1])%2, boardsize).astype(int)
print(checkerboard((10,15), (2,3)))
[[0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]
[0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]
[1 1 1 0 0 0 1 1 1 0 0 0 1 1 1]
[1 1 1 0 0 0 1 1 1 0 0 0 1 1 1]
[0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]
[0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]
[1 1 1 0 0 0 1 1 1 0 0 0 1 1 1]
[1 1 1 0 0 0 1 1 1 0 0 0 1 1 1]
[0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]
[0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]]
Replace n with an even number and you will get the answer.
import numpy as np
b = np.array([[0,1],[1,0]])
np.tile(b,(n, n))
Based on Eelco Hoogendoorn's answer, if you want a checkerboard with various tile sizes you can use this:
def checkerboard(shape, tile_size):
return (np.indices(shape) // tile_size).sum(axis=0) % 2
I modified hass's answer as follows.
import math
import numpy as np
def checkerboard(w, h, c0, c1, blocksize):
tile = np.array([[c0,c1],[c1,c0]]).repeat(blocksize, axis=0).repeat(blocksize, axis=1)
grid = np.tile(tile,(int(math.ceil((h+0.0)/(2*blocksize))),int(math.ceil((w+0.0)/(2*blocksize)))))
return grid[:h,:w]
Using tile function :
import numpy as np
n = int(input())
x = np.tile(arr,(n,n//2))
x[1::2, 0::2] = 1
x[0::2, 1::2] = 1
print(x)
Very very late, but I needed a solution that allows for a non-unit checker size on an arbitrarily sized checkerboard. Here's a simple and fast solution:
import numpy as np
def checkerboard(shape, dw):
"""Create checkerboard pattern, each square having width ``dw``.
Returns a numpy boolean array.
"""
# Create individual block
block = np.zeros((dw * 2, dw * 2), dtype=bool)
block[dw:, :dw] = 1
block[:dw, dw:] = 1
# Tile until we exceed the size of the mask, then trim
repeat = (np.array(shape) + dw * 2) // np.array(block.shape)
trim = tuple(slice(None, s) for s in shape)
checkers = np.tile(block, repeat)[trim]
assert checkers.shape == shape
return checkers
To convert the checkerboard squares to colors, you could do:
checkers = checkerboard(shape, dw)
img = np.empty_like(checkers, dtype=np.uint8)
img[checkers] = 0xAA
img[~checkers] = 0x99
import numpy as np
n = int(input())
arr = ([0, 1], [1,0])
print(np.tile(arr, (n//2,n//2)))
For input 6, output:
[[0 1 0 1 0 1]
[1 0 1 0 1 0]
[0 1 0 1 0 1]
[1 0 1 0 1 0]
[0 1 0 1 0 1]
[1 0 1 0 1 0]]
I recently want the same function and i modified doug's answer a little bit as follows:
def gen_checkerboard(grid_num, grid_size):
row_even = grid_num/2 * [0,1]
row_odd = grid_num/2 * [1,0]
checkerboard = numpy.row_stack(grid_num/2*(row_even, row_odd))
return checkerboard.repeat(grid_size, axis = 0).repeat(grid_size, axis = 1)
Simplest implementation of the same.
import numpy as np
n = int(input())
checkerboard = np.tile(np.array([[0,1],[1,0]]), (n//2, n//2))
print(checkerboard)
n = int(input())
import numpy as np
m=int(n/2)
a=np.array(([0,1]*m+[1,0]*m)*m).reshape((n,n))
print (a)
So if input is n = 4 then output would be like:
[[0 1 0 1]
[1 0 1 0]
[0 1 0 1]
[1 0 1 0]]
Simplest way to write checkboard matrix using tile()
array = np.tile([0,1],n//2)
array1 = np.tile([1,0],n//2)
finalArray = np.array([array, array1], np.int32)
finalArray = np.tile(finalArray,(n//2,1))
Suppose we need a patter with length and breadth (even number) as l, b.
base_matrix = np.array([[0,1],[1,0]])
As this base matrix, which would be used as a tile already has length and breadth of 2 X 2, we would need to divide by 2.
print np.tile(base_matrix, (l / 2, b / 2))
print (np.tile(base,(4/2,6/2)))
[[0 1 0 1 0 1]
[1 0 1 0 1 0]
[0 1 0 1 0 1]
[1 0 1 0 1 0]]
n = int(input())
import numpy as np
a = np.array([0])
x = np.tile(a,(n,n))
x[1::2, ::2] = 1
x[::2, 1::2] = 1
print(x)
I guess this works perfectly well using numpy.tile( ) function.
Here is the solution using tile function in numpy.
import numpy as np
x = np.array([[0, 1], [1, 0]])
check = np.tile(x, (n//2, n//2))
# Print the created matrix
print(check)
for input 2, the Output is
[[0 1]
[1 0]]
for input 4, the Output is
[[0 1 0 1]
[1 0 1 0]
[0 1 0 1]
[1 0 1 0]]
Given odd or even 'n', below approach generates "arr" in the checkerboard pattern and does not use loops. If n is odd, this is extremely straightforward to use. If n is even, we generate the checkerboard for n-1 and then add an extra row and column.
rows = n-1 if n%2 == 0 else n
arr=(rows*rows)//2*[0,1]
arr.extend([0])
arr = np.reshape(arr, (rows,rows))
if n%2 == 0:
extra = (n//2*[1,0])
arr = np.concatenate((arr, np.reshape(extra[:-1], (1,n-1))))
arr = np.concatenate((arr, np.reshape(extra, (n,1))), 1)
Here is a generalisation to falko's answer
import numpy as np
def checkerboard(width,sq):
'''
width --> the checkerboard will be of size width x width
sq ---> each square inside the checkerboard will be of size sq x sq
'''
rep = int(width/(2*sq))
return np.kron([[1, 0] * rep, [0, 1] * rep] * rep, np.ones((sq, sq))).astype(np.uint8)
x = checkerboard(width=8,sq=4)
print(x)
print('checkerboard is of size ',x.shape)
which gives the following output
[[1 1 1 1 0 0 0 0]
[1 1 1 1 0 0 0 0]
[1 1 1 1 0 0 0 0]
[1 1 1 1 0 0 0 0]
[0 0 0 0 1 1 1 1]
[0 0 0 0 1 1 1 1]
[0 0 0 0 1 1 1 1]
[0 0 0 0 1 1 1 1]]
checkerboard is of size (8, 8)
Here's a numpy solution with some checking to make sure that the width and height are evenly divisible by the square size.
def make_checkerboard(w, h, sq, fore_color, back_color):
"""
Creates a checkerboard pattern image
:param w: The width of the image desired
:param h: The height of the image desired
:param sq: The size of the square for the checker pattern
:param fore_color: The foreground color
:param back_color: The background color
:return:
"""
w_rem = np.mod(w, sq)
h_rem = np.mod(w, sq)
if w_rem != 0 or h_rem != 0:
raise ValueError('Width or height is not evenly divisible by square '
'size.')
img = np.zeros((h, w, 3), dtype='uint8')
x_divs = w // sq
y_divs = h // sq
fore_tile = np.ones((sq, sq, 3), dtype='uint8')
fore_tile *= np.array([[fore_color]], dtype='uint8')
back_tile = np.ones((sq, sq, 3), dtype='uint8')
back_tile *= np.array([[back_color]], dtype='uint8')
for y in np.arange(y_divs):
if np.mod(y, 2):
b = back_tile
f = fore_tile
else:
b = fore_tile
f = back_tile
for x in np.arange(x_divs):
if np.mod(x, 2) == 0:
img[y * sq:y * sq + sq, x * sq:x * sq + sq] = f
else:
img[y * sq:y * sq + sq, x * sq:x * sq + sq] = b
return img

Categories

Resources